Pull PSReadLine from PSGallery (#5759)

Instead of building PSReadLine from this repo, pull it from the gallery using nuget cache.

This pulls v2.0 of PSReadLine which does have documented breaking changes from v1.2, but the risk is small - the features that have changed are typically only used in a profile and aren't used all that often anyway.

Fix #996

Hardcodes version of modules pulled from PSGallery
This commit is contained in:
Jason Shirk 2018-01-19 18:15:09 -08:00 committed by Travis Plunk
parent 65a4002990
commit beffdcf94d
59 changed files with 57 additions and 17523 deletions

View file

@ -21,7 +21,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Management.Infras
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.Commands.Diagnostics", "src\Microsoft.PowerShell.Commands.Diagnostics\Microsoft.PowerShell.Commands.Diagnostics.csproj", "{439A24FC-8E0A-48B6-8227-44C297311F49}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.PSReadLine", "src\Microsoft.PowerShell.PSReadLine\Microsoft.PowerShell.PSReadLine.csproj", "{07BFD271-8992-4F34-9091-6CFC3E224A24}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.WSMan.Management", "src\Microsoft.WSMan.Management\Microsoft.WSMan.Management.csproj", "{8F63D134-E413-4181-936D-D82F3F5F1D85}"
EndProject

View file

@ -521,9 +521,7 @@ Fix steps:
# handle Restore
if ($Restore -or -not (Test-Path "$($Options.Top)/obj/project.assets.json")) {
log "Run dotnet restore"
$srcProjectDirs = @($Options.Top, "$PSScriptRoot/src/TypeCatalogGen", "$PSScriptRoot/src/ResGen")
$srcProjectDirs = @($Options.Top, "$PSScriptRoot/src/TypeCatalogGen", "$PSScriptRoot/src/ResGen", "$PSScriptRoot/src/Modules/PSGalleryModules.csproj")
$testProjectDirs = Get-ChildItem "$PSScriptRoot/test/*.csproj" -Recurse | ForEach-Object { [System.IO.Path]::GetDirectoryName($_) }
$RestoreArguments = @("--verbosity")
@ -533,7 +531,11 @@ Fix steps:
$RestoreArguments += "quiet"
}
($srcProjectDirs + $testProjectDirs) | ForEach-Object { Start-NativeExecution { dotnet restore $_ $RestoreArguments } }
($srcProjectDirs + $testProjectDirs) | ForEach-Object {
log "Run dotnet restore $_ $RestoreArguments"
Start-NativeExecution { dotnet restore $_ $RestoreArguments }
}
}
# handle ResGen
@ -646,17 +648,11 @@ function Restore-PSModuleToBuild
$CI
)
$ProgressPreference = "SilentlyContinue"
log "Restore PowerShell modules to $publishPath"
$modulesDir = Join-Path -Path $publishPath -ChildPath "Modules"
# Restore modules from powershellgallery feed
Restore-PSModule -Destination $modulesDir -Name @(
# PowerShellGet depends on PackageManagement module, so PackageManagement module will be installed with the PowerShellGet module.
'PowerShellGet'
'Microsoft.PowerShell.Archive'
) -SourceLocation "https://www.powershellgallery.com/api/v2/"
Copy-PSGalleryModules -Destination $modulesDir
if($CI.IsPresent)
{
@ -675,6 +671,7 @@ function Restore-PSPester
Restore-GitModule -Destination $Destination -Uri 'https://github.com/PowerShell/psl-pester' -Name Pester -CommitSha '1f546b6aaa0893e215e940a14f57c96f56f7eff1'
}
function Compress-TestContent {
[CmdletBinding()]
param(
@ -2355,7 +2352,6 @@ function Start-CrossGen {
"Microsoft.PowerShell.Security.dll",
"Microsoft.PowerShell.CoreCLR.Eventing.dll",
"Microsoft.PowerShell.ConsoleHost.dll",
"Microsoft.PowerShell.PSReadLine.dll",
"System.Management.Automation.dll"
)
@ -2464,102 +2460,56 @@ function Restore-GitModule
}
# Install PowerShell modules such as PackageManagement, PowerShellGet
function Restore-PSModule
function Copy-PSGalleryModules
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string[]]$Name,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$Destination,
[string]$SourceLocation="https://powershell.myget.org/F/powershellmodule/api/v2/",
[string]$RequiredVersion
[string]$Destination
)
$needRegister = $true
$RepositoryName = "mygetpsmodule"
# Check if the PackageManagement works in the base-oS or PowerShellCore
$null = Get-PackageProvider -Name NuGet -ForceBootstrap -Verbose:$VerbosePreference
$null = Get-PackageProvider -Name PowerShellGet -Verbose:$VerbosePreference
# Get the existing registered PowerShellGet repositories
$psrepos = PowerShellGet\Get-PSRepository
foreach ($repo in $psrepos)
{
if(($repo.SourceLocation -eq $SourceLocation) -or ($repo.SourceLocation.TrimEnd("/") -eq $SourceLocation.TrimEnd("/")))
{
# found a registered repository that matches the source location
$needRegister = $false
$RepositoryName = $repo.Name
break
}
if (!$Destination.EndsWith("Modules")) {
throw "Installing to an unexpected location"
}
if($needRegister)
{
$regVar = PowerShellGet\Get-PSRepository -Name $RepositoryName -ErrorAction SilentlyContinue
if($regVar)
{
PowerShellGet\UnRegister-PSRepository -Name $RepositoryName
}
log "Registering PSRepository with name: $RepositoryName and sourcelocation: $SourceLocation"
PowerShellGet\Register-PSRepository -Name $RepositoryName -SourceLocation $SourceLocation -ErrorVariable ev -verbose
if($ev)
{
throw ("Failed to register repository '{0}'" -f $RepositoryName)
}
$regVar = PowerShellGet\Get-PSRepository -Name $RepositoryName
if(-not $regVar)
{
throw ("'{0}' is not registered" -f $RepositoryName)
}
$cache = dotnet nuget locals global-packages -l
if ($cache -match "info : global-packages: (.*)") {
$nugetCache = $matches[1]
}
else {
throw "Can't find nuget global cache"
}
log ("Name='{0}', Destination='{1}', Repository='{2}'" -f ($Name -join ','), $Destination, $RepositoryName)
$psGalleryProj = [xml](Get-Content -Raw $PSScriptRoot\src\Modules\PSGalleryModules.csproj)
# do not output progress
$ProgressPreference = "SilentlyContinue"
$Name | ForEach-Object {
foreach ($m in $psGalleryProj.Project.ItemGroup.PackageReference) {
$name = $m.Include
$version = $m.Version
log "Name='$Name', Version='$version', Destination='$Destination'"
$command = @{
Name=$_
Path = $Destination
Repository =$RepositoryName
}
if($RequiredVersion)
{
$command.Add("RequiredVersion", $RequiredVersion)
# Remove the build revision from the src (nuget drops it).
$srcVer = if ($version -match "(\d+.\d+.\d+).\d+") {
$matches[1]
} else {
$version
}
#
# Remove semantic version in the destination directory
$destVer = if ($version -match "(\d+.\d+.\d+)-.+") {
$matches[1]
} else {
$version
}
# pull down the module
log "running save-module $_"
PowerShellGet\Save-Module @command -Force
# Nuget seems to always use lowercase in the cache
$src = "$nugetCache/$($name.ToLower())/$srcVer"
$dest = "$Destination/$name/$destVer"
# Remove PSGetModuleInfo.xml file
Find-Module -Name $_ -Repository $RepositoryName -IncludeDependencies | ForEach-Object {
Remove-Item -Path $Destination\$($_.Name)\*\PSGetModuleInfo.xml -Force
}
}
# Clean up
if($needRegister)
{
$regVar = PowerShellGet\Get-PSRepository -Name $RepositoryName -ErrorAction SilentlyContinue
if($regVar)
{
log "Unregistering PSRepository with name: $RepositoryName"
PowerShellGet\UnRegister-PSRepository -Name $RepositoryName
}
Remove-Item -Force -ErrorAction Ignore -Recurse "$Destination/$name"
New-Item -Path $dest -ItemType Directory -Force -ErrorAction Stop > $null
$dontCopy = '*.nupkg', '*.nupkg.sha512', '*.nuspec', 'System.Runtime.InteropServices.RuntimeInformation.dll'
Copy-Item -Exclude $dontCopy -Recurse $src/* $dest
}
}

View file

@ -16,7 +16,7 @@ We are calling `dotnet` tool build for `$Top` directory
### Dummy dependencies
We use dummy dependencies between projects to leverage `dotnet` build functionality.
For example, `src\powershell-win-core\powershell-win-core.csproj` has dependency on `Microsoft.PowerShell.PSReadLine`,
For example, `src\powershell-win-core\powershell-win-core.csproj` has dependency on `Microsoft.PowerShell.Commands.Diagnostics.csproj`,
but in reality, there is no build dependency.
Dummy dependencies allows us to build just `$Top` folder, instead of building several folders.

View file

@ -19,7 +19,6 @@ The following table shows the status for the above commit, dated 06/18/2017
| Microsoft.PowerShell.CoreCLR.AssemblyLoadContext | 97.65% |
| Microsoft.PowerShell.CoreCLR.Eventing | 29.91% |
| Microsoft.PowerShell.LocalAccounts | 86.35% |
| Microsoft.PowerShell.PSReadLine | 10.18% |
| Microsoft.PowerShell.Security | 44.44% |
| Microsoft.WSMan.Management | 4.91% |
| System.Management.Automation | 50.42% |
@ -52,10 +51,6 @@ The following table shows the status for the above commit, dated 06/18/2017
- [ ] Add tests for ETW events. [#4156](https://github.com/PowerShell/PowerShell/issues/4156)
### Microsoft.PowerShell.PSReadLine
- [ ] We need tests from PSReadline repo or ignore coverage data for this module. (This will be filtered out.)
### Microsoft.PowerShell.Security
- [ ] Add tests for *-Acl cmdlets. [4157] (https://github.com/PowerShell/PowerShell/issues/4157)

View file

@ -5,5 +5,6 @@
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
<add key="powershell-core" value="https://powershell.myget.org/F/powershell-core/api/v3/index.json" />
<add key="PSGallery" value="https://www.powershellgallery.com/api/v2/" />
</packageSources>
</configuration>

View file

@ -1,19 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTrademark("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("36053fb0-0bd0-4a1c-951c-b2ec109deca3")]

View file

@ -1,579 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Language;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell.Internal;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
/// <summary>
/// Insert the key
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SelfInsert(ConsoleKeyInfo? key = null, object arg = null)
{
if (!key.HasValue)
{
return;
}
if (arg is int)
{
var count = (int)arg;
if (count <= 0)
return;
if (count > 1)
{
var toInsert = new string(key.Value.KeyChar, count);
if (_singleton._visualSelectionCommandCount > 0)
{
int start, length;
_singleton.GetRegion(out start, out length);
Replace(start, length, toInsert);
}
else
{
Insert(toInsert);
}
return;
}
}
if (_singleton._visualSelectionCommandCount > 0)
{
int start, length;
_singleton.GetRegion(out start, out length);
Replace(start, length, new string(key.Value.KeyChar, 1));
}
else
{
Insert(key.Value.KeyChar);
}
}
/// <summary>
/// Reverts all of the input to the current input.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void RevertLine(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton._statusIsErrorMessage)
{
// After an edit, clear the error message
_singleton.ClearStatusMessage(render: false);
}
while (_singleton._undoEditIndex > 0)
{
_singleton._edits[_singleton._undoEditIndex - 1].Undo();
_singleton._undoEditIndex--;
}
_singleton.Render();
}
/// <summary>
/// Cancel the current input, leaving the input on the screen,
/// but returns back to the host so the prompt is evaluated again.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void CancelLine(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.ClearStatusMessage(false);
_singleton._current = _singleton._buffer.Length;
// We want to display ^C to show the line was canceled. Instead of appending ^C
// (or (char)3), we append 2 spaces so we don't affect tokenization too much, e.g.
// changing a keyword to a command.
_singleton._buffer.Append(" ");
_singleton.ReallyRender();
// Now that we've rendered with this extra spaces, go back and replace the spaces
// with ^C colored in red (so it stands out.)
var coordinates = _singleton.ConvertOffsetToCoordinates(_singleton._current);
var console = _singleton._console;
var consoleBuffer = _singleton._consoleBuffer;
int i = (coordinates.Y - _singleton._initialY) * console.BufferWidth + coordinates.X;
consoleBuffer[i].UnicodeChar = '^';
consoleBuffer[i].ForegroundColor = ConsoleColor.Red;
consoleBuffer[i].BackgroundColor = console.BackgroundColor;
consoleBuffer[i+1].UnicodeChar = 'C';
consoleBuffer[i+1].ForegroundColor = ConsoleColor.Red;
consoleBuffer[i+1].BackgroundColor = console.BackgroundColor;
console.WriteBufferLines(consoleBuffer, ref _singleton._initialY);
var y = coordinates.Y + 1;
_singleton.PlaceCursor(0, ref y);
_singleton._buffer.Clear(); // Clear so we don't actually run the input
_singleton._current = 0; // If Render is called, _current must be correct.
_singleton._currentHistoryIndex = _singleton._history.Count;
_singleton._inputAccepted = true;
}
/// <summary>
/// Like ForwardKillLine - deletes text from the point to the end of the line,
/// but does not put the deleted text in the kill ring.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ForwardDeleteLine(ConsoleKeyInfo? key = null, object arg = null)
{
var current = _singleton._current;
var buffer = _singleton._buffer;
if (buffer.Length > 0 && current < buffer.Length)
{
int length = buffer.Length - current;
var str = buffer.ToString(current, length);
_singleton.SaveEditItem(EditItemDelete.Create(str, current));
buffer.Remove(current, length);
_singleton.Render();
}
}
/// <summary>
/// Like BackwardKillLine - deletes text from the point to the start of the line,
/// but does not put the deleted text in the kill ring.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void BackwardDeleteLine(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton._current > 0)
{
_singleton._clipboard = _singleton._buffer.ToString(0, _singleton._current);
_singleton.SaveEditItem(EditItemDelete.Create(_singleton._clipboard, 0));
_singleton._buffer.Remove(0, _singleton._current);
_singleton._current = 0;
_singleton.Render();
}
}
/// <summary>
/// Delete the character before the cursor.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void BackwardDeleteChar(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton._visualSelectionCommandCount > 0)
{
int start, length;
_singleton.GetRegion(out start, out length);
Delete(start, length);
return;
}
if (_singleton._buffer.Length > 0 && _singleton._current > 0)
{
int qty = (arg is int) ? (int) arg : 1;
qty = Math.Min(qty, _singleton._current);
int startDeleteIndex = _singleton._current - qty;
_singleton.SaveEditItem(
EditItemDelete.Create(
_singleton._buffer.ToString(startDeleteIndex, qty),
startDeleteIndex,
BackwardDeleteChar,
arg)
);
_singleton.SaveToClipboard(startDeleteIndex, qty);
_singleton._buffer.Remove(startDeleteIndex, qty);
_singleton._current = startDeleteIndex;
_singleton.Render();
}
else
{
Ding();
}
}
private void DeleteCharImpl(int qty, bool orExit)
{
qty = Math.Min(qty, _singleton._buffer.Length + 1 + ViEndOfLineFactor - _singleton._current);
if (_visualSelectionCommandCount > 0)
{
int start, length;
GetRegion(out start, out length);
Delete(start, length);
return;
}
if (_buffer.Length > 0)
{
if (_current < _buffer.Length)
{
SaveEditItem(EditItemDelete.Create(_buffer.ToString(_current, qty), _current, DeleteChar, qty));
SaveToClipboard(_current, qty);
_buffer.Remove(_current, qty);
if (_current >= _buffer.Length)
{
_current = Math.Max(0, _buffer.Length - 1);
}
Render();
}
}
else if (orExit)
{
throw new ExitException();
}
}
/// <summary>
/// Delete the character under the cursor.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void DeleteChar(ConsoleKeyInfo? key = null, object arg = null)
{
int qty = (arg is int) ? (int)arg : 1;
_singleton.DeleteCharImpl(qty, orExit: false);
}
/// <summary>
/// Delete the character under the cursor, or if the line is empty, exit the process
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void DeleteCharOrExit(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.DeleteCharImpl(1, orExit: true);
}
private bool AcceptLineImpl(bool validate)
{
ParseInput();
if (_parseErrors.Any(e => e.IncompleteInput))
{
Insert('\n');
return false;
}
// If text was pasted, for performance reasons we skip rendering for some time,
// but if input is accepted, we won't have another chance to render.
//
// Also - if there was an emphasis, we want to clear that before accepting
// and that requires rendering.
bool renderNeeded = _emphasisStart >= 0 || _queuedKeys.Count > 0;
_emphasisStart = -1;
_emphasisLength = 0;
var insertionPoint = _current;
// Make sure cursor is at the end before writing the line
_current = _buffer.Length;
if (renderNeeded)
{
ReallyRender();
}
// Only run validation if we haven't before. If we have and status line shows an error,
// treat that as a -Force and accept the input so it is added to history, and PowerShell
// can report an error as it normally does.
if (validate && !_statusIsErrorMessage)
{
var errorMessage = Validate(_ast);
if (!string.IsNullOrWhiteSpace(errorMessage))
{
// If there are more keys, assume the user pasted with a right click and
// we should insert a newline even though validation failed.
if (_queuedKeys.Count > 0)
{
// Validation may have moved the cursor. Because there are queued
// keys, we need to move the cursor back to the correct place, and
// ignore where validation put the cursor because the queued keys
// will be inserted in the wrong place.
SetCursorPosition(insertionPoint);
Insert('\n');
}
_statusLinePrompt = "";
_statusBuffer.Append(errorMessage);
_statusIsErrorMessage = true;
Render();
return false;
}
}
if (_statusIsErrorMessage)
{
ClearStatusMessage(render: true);
}
var coordinates = ConvertOffsetToCoordinates(_current);
var y = coordinates.Y + 1;
PlaceCursor(0, ref y);
_inputAccepted = true;
return true;
}
class CommandValidationVisitor : AstVisitor
{
private readonly Ast _rootAst;
internal string detectedError;
internal CommandValidationVisitor(Ast rootAst)
{
_rootAst = rootAst;
}
public override AstVisitAction VisitCommand(CommandAst commandAst)
{
var commandName = commandAst.GetCommandName();
if (commandName != null)
{
if (_singleton._engineIntrinsics != null)
{
var commandInfo = _singleton._engineIntrinsics.InvokeCommand.GetCommand(commandName, CommandTypes.All);
if (commandInfo == null && !_singleton.UnresolvedCommandCouldSucceed(commandName, _rootAst))
{
_singleton._current = commandAst.CommandElements[0].Extent.EndOffset;
detectedError = string.Format(CultureInfo.CurrentCulture, PSReadLineResources.CommandNotFoundError, commandName);
return AstVisitAction.StopVisit;
}
}
if (commandAst.CommandElements.Any(e => e is ScriptBlockExpressionAst))
{
if (_singleton._options.CommandsToValidateScriptBlockArguments == null ||
!_singleton._options.CommandsToValidateScriptBlockArguments.Contains(commandName))
{
return AstVisitAction.SkipChildren;
}
}
}
if (_singleton._options.CommandValidationHandler != null)
{
try
{
_singleton._options.CommandValidationHandler(commandAst);
}
catch (Exception e)
{
detectedError = e.Message;
}
}
return !string.IsNullOrWhiteSpace(detectedError)
? AstVisitAction.StopVisit
: AstVisitAction.Continue;
}
}
private string Validate(Ast rootAst)
{
if (_parseErrors != null && _parseErrors.Length > 0)
{
// Move the cursor to the point of error
_current = _parseErrors[0].Extent.EndOffset;
return _parseErrors[0].Message;
}
var validationVisitor = new CommandValidationVisitor(rootAst);
rootAst.Visit(validationVisitor);
if (!string.IsNullOrWhiteSpace(validationVisitor.detectedError))
{
return validationVisitor.detectedError;
}
return null;
}
private bool UnresolvedCommandCouldSucceed(string commandName, Ast rootAst)
{
// This is a little hacky, but we check for a few things where part of the current
// command defines/imports new commands that PowerShell might not yet know about.
// There is little reason to go to great lengths at being correct here, validation
// is just a small usability tweak to avoid cluttering up history - PowerShell
// will report errors for stuff we actually let through.
// Do we define a function matching the command name?
var fnDefns = rootAst.FindAll(ast => ast is FunctionDefinitionAst, true).OfType<FunctionDefinitionAst>();
if (fnDefns.Any(fnDefnAst => fnDefnAst.Name.Equals(commandName, StringComparison.OrdinalIgnoreCase)))
{
return true;
}
var cmdAsts = rootAst.FindAll(ast => ast is CommandAst, true).OfType<CommandAst>();
foreach (var cmdAst in cmdAsts)
{
// If we dot source something, we can't in general know what is being
// dot sourced so just assume the unresolved command will work.
// If we use the invocation operator, allow that because an expression
// is being invoked and it's reasonable to just allow it.
if (cmdAst.InvocationOperator != TokenKind.Unknown)
{
return true;
}
// Are we importing a module or being tricky with Invoke-Expression? Let those through.
var candidateCommand = cmdAst.GetCommandName();
if (candidateCommand.Equals("Import-Module", StringComparison.OrdinalIgnoreCase)
|| candidateCommand.Equals("ipmo", StringComparison.OrdinalIgnoreCase)
|| candidateCommand.Equals("Invoke-Expression", StringComparison.OrdinalIgnoreCase)
|| candidateCommand.Equals("iex", StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
if (commandName.Length == 1)
{
switch (commandName[0])
{
// The following are debugger commands that should be accepted if we're debugging
// because the console host will interpret these commands directly.
case 's': case 'v': case 'o': case 'c': case 'q': case 'k': case 'l':
case 'S': case 'V': case 'O': case 'C': case 'Q': case 'K': case 'L':
case '?': case 'h': case 'H':
// Ideally we would check $PSDebugContext, but it is set at function
// scope, and because we're in a module, we can't find that variable
// (arguably a PowerShell issue.)
// NestedPromptLevel is good enough though - it's rare to be in a nested.
var nestedPromptLevel = _engineIntrinsics.SessionState.PSVariable.GetValue("NestedPromptLevel");
if (nestedPromptLevel is int)
{
return ((int)nestedPromptLevel) > 0;
}
break;
}
}
return false;
}
static bool StaticParameterBindingSupported(CommandInfo commandInfo)
{
var aliasInfo = commandInfo as AliasInfo;
if (aliasInfo != null)
{
commandInfo = aliasInfo.ResolvedCommand;
}
return (commandInfo is ExternalScriptInfo)
|| (commandInfo is CmdletInfo)
|| (commandInfo is FunctionInfo);
}
/// <summary>
/// Attempt to execute the current input. If the current input is incomplete (for
/// example there is a missing closing parenthesis, bracket, or quote, then the
/// continuation prompt is displayed on the next line and PSReadline waits for
/// keys to edit the current input.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void AcceptLine(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.AcceptLineImpl(false);
}
/// <summary>
/// Attempt to execute the current input. If the current input is incomplete (for
/// example there is a missing closing parenthesis, bracket, or quote, then the
/// continuation prompt is displayed on the next line and PSReadline waits for
/// keys to edit the current input.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ValidateAndAcceptLine(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.AcceptLineImpl(true);
}
/// <summary>
/// Attempt to execute the current input. If it can be executed (like AcceptLine),
/// then recall the next item from history the next time Readline is called.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void AcceptAndGetNext(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton.AcceptLineImpl(false))
{
if (_singleton._currentHistoryIndex < (_singleton._history.Count - 1))
{
_singleton._getNextHistoryIndex = _singleton._currentHistoryIndex + 1;
}
else
{
Ding();
}
}
}
/// <summary>
/// The continuation prompt is displayed on the next line and PSReadline waits for
/// keys to edit the current input. This is useful to enter multi-line input as
/// a single command even when a single line is complete input by itself.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void AddLine(ConsoleKeyInfo? key = null, object arg = null)
{
Insert('\n');
}
/// <summary>
/// A new empty line is created above the current line regardless of where the cursor
/// is on the current line. The cursor moves to the beginning of the new line.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void InsertLineAbove(ConsoleKeyInfo? key = null, object arg = null)
{
// Move the current position to the beginning of the current line and only the current line.
if (_singleton.LineIsMultiLine())
{
int i = Math.Max(0, _singleton._current - 1);
for (; i > 0; i--)
{
if (_singleton._buffer[i] == '\n')
{
i += 1;
break;
}
}
_singleton._current = i;
}
else
{
_singleton._current = 0;
}
Insert('\n');
PreviousLine();
}
/// <summary>
/// A new empty line is created below the current line regardless of where the cursor
/// is on the current line. The cursor moves to the beginning of the new line.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void InsertLineBelow(ConsoleKeyInfo? key = null, object arg = null)
{
// Move the current position to the end of the current line and only the current line.
if (_singleton.LineIsMultiLine())
{
int i = _singleton._current;
for (; i < _singleton._buffer.Length; i++)
{
if (_singleton._buffer[i] == '\n')
{
break;
}
}
_singleton._current = i;
}
else
{
_singleton._current = _singleton._buffer.Length;
}
Insert('\n');
}
}
}

View file

@ -1,293 +0,0 @@
### Version 1.2
New features:
* Vi editing mode
New functions:
* InsertLineAbove
- A new empty line is created above the current line regardless of where the cursor
is on the current line. The cursor moves to the beginning of the new line.
* InsertLineBelow
- A new empty line is created below the current line regardless of where the cursor
is on the current line. The cursor moves to the beginning of the new line.
New key bindings:
* Ctrl+Enter bound to InsertLineAbove in Windows mode
* Ctrl+Shift+Enter bound to InsertLineBelow in Windows mode
Bug fixes:
* Home the first line of multi-line input fixed
* CaptureScreen captures colors colors correctly instead of guessing
* CaptureScreen scrolls the screen to ensure the selected line is visible
* CaptureScreen allows j/k for up/down (for the vi fans)
* Fixed uncommon syntax coloring bug with bare words that start with a variable
* Added sample handler for F7 emulation
* Fixed sample handler for Set-StrictMode error
* Improved error message when errors occur in custom handlers
### Version 1.1 (shipped w/ Windows 10)
Breaking change:
* Namespace PSConsoleUtilities has been renamed to Microsoft.PowerShell
* Default history file location changed to match Windows 10
### Version 1.0.0.13
New features:
* Enter now does some extra validation before accepting the input. If there are any parse
errors or a command is not found, an error message is displayed, but you can continue editing,
the erroneous line will not be added to history, and the error message will be cleared after
you make an edit.
You can press Enter a second time to force accepting the line if you choose.
If you don't like the new behavior for Enter, you can revert to the old behavior with:
Set-PSReadlineKeyHandler -Key Enter -Function AcceptLine
Bug fixes:
* Occasional exception with AcceptAndGetNext (Ctrl+O) followed by something other than Enter
* Event handlers that register for the engine event PowerShell.OnIdle should work now.
* ClearScreen now scrolls the screen to preserve as much output as possible
* Fix exception on error input during rendering after certain keywords like process, begin, or end.
* Fix exception after undo from menu completion
* Support CancelLine (Ctrl+C) and Abort (Ctrl+G in emacs) to cancel DigitArgument
* History recall now ignores command lines from other currently running sessions, but you can
still find command lines from those sessions when searching history.
* Color any non-whitespace prompt character when there is an error, not just non-characters
* ScrollDisplayToCursor works a little better now.
New functions:
* ValidateAndAcceptLine
Validate the command line (by making sure there are no parse errors, commands all exist,
and possibly other sorts of validation), display an error if any errors, but don't add
the command to history and clear the error after an edit.
* DeleteCharOrExit
- emulate Ctrl+D in bash properly by exiting the process if the command line is empty
* ScrollDisplayUpLine, ScrollDisplayDownLine
Scroll the screen up or down by a line instead of by the screen
New key bindings:
* Ctrl+D bound to DeleteCharOrExit in Emacs mode
* Ctrl+N/Ctrl+P bound to NextHistory/PreviousHistory in Emacs mode
* Ctrl+PageUp bound to ScrollDisplayUpLine
* Ctrl+PageDown bound to ScrollDisplayDownLine
* Alt+F7 bound to ClearHistory in Windows mode
New options:
* Set-PSReadlineOption
-ErrorForegroundColor
-ErrorBackgroundColor
Colors used when ValidateAndAcceptLine reports an error
-CommandValidationHandler
A delegate that is called from ValidateAndAcceptLine that can perform custom validation
and also fix the command line, e.g. to correct common typos.
New cmdlet:
* Remove-PSReadlineKeyHandler
This will remove a key binding for previously bound keys.
Breaking change:
* Demo mode removed
- Trying to bind functions EnableDemoMode or DisableDemoMode will result in an error.
### Version 1.0.0.12
New features:
* Multi-line editing is now practical. Home/End go to the start/end of the current line or
start/end of the input in a reasonable way. Up/Down arrows will move across lines if the
input has multiple lines and you are not in the middle of recalling history.
Bug fixes:
* Color the prompt character if there is an error for any non-alphanumeric character
* Fix an issue related to undo (which was commonly hit via Escape) and using history search
* Fix a bug where PowerShell events are not written to the console until PSReadline returns
* Fixed so PowerTab now works with PSReadline
* Highlight from history search is cleared before accepting a line now.
* Fixed MenuComplete so it clears the menu (which only happened on some systems)
New functions:
* NextLine
* PreviousLine
- These functions are added for completeness, neither is particularly useful as the usual
bindings for UpArrow/DownArrow are smart enough to recall history or change lines
depending on the context.
New key bindings:
* F8/Shift+F8 bound to HistorySearchBackward/HistorySearchForward in Windows mode
### Version 1.0.0.11
Bug fixes:
* Fixed MenuComplete to actually work
### Version 1.0.0.10
New features:
* Added binding Ctrl+SpaceBar to MenuComplete in Windows and Emacs modes
- If you want to old behavior of Ctrl+Spacebar, bind it to PossibleCompletions
* Added binding Alt+. (YankLastArg) to Windows mode
* Added diagnostics when an exception occurs to help reporting bugs
Bug fixes:
* SaveHistoryPath option fixed
* Fix ShowKeyBindings to not write blank lines
* Fixed bug with undo
### Version 1.0.0.9
New features:
* MenuComplete - like an interactive show completion
* Automatically save history
- at process exit
- incrementally and shared across sessions
- don't save
See parameters HistorySaveStyle and HistorySavePath to Set-PSReadlineOption
* Added sample custom binding for quickly changing directories in SamplePSReadlineProfile.ps1
Bug fixes:
* Items loaded from history work with RevertLine
* Recalling current line after up arrow works again
### Version 1.0.0.8
New features:
* SamplePSReadlineProfile.ps1 added with examples of custom key bindings
* Word movement takes DigitArgument
* HistoryNoDuplicates now works a little differently
- Duplicates are saved (it was a dubious memory optimization anyway)
- Recall will recall the most recently executed item instead of the first
* When at the last word, NextWord/ForwardWord now move to the end of line instead
of the last character of the word.
* HistorySearchBackward/HistorySearchForward changes behavior slightly:
- use emphasis like InteractiveHistorySearch
- cursor always moves to end like PreviousHistory/NextHistory
* New api GetSelectionState to get the current selection (if any).
* New functions:
- SelectBackwardsLine
- SelectLine
- SelectAll
- CopyOrCancelLine
* New key bindings in Windows mode:
- Alt+0 through Alt+9 and Alt+-: DigitArgument
- Ctrl+R/Ctrl+S for interactive history search
Bug fixes:
* Backspace after a failed interactive history search (Ctrl+R) caused searching
to fail if you typed anything other than backspace.
### Version 1.0.0.7
New features:
* CaptureScreen - copies selected portion of screen to clipboard in text and rtf
* InvokePrompt - re-evaluate the prompt while preserving the current input
* New functions to scroll the screen w/o using the mouse:
- ScrollScreenUp
- ScrollScreenDown
- ScrollScreenTop
- ScrollScreenToCursor
* Many small bug fixes
### Version 1.0.0.6
New features:
* CharacterSearch/CharacterSearchBackward
* AcceptAndGetNext (Ctrl+O in bash)
* Get-PSReadlineKeyHandler now returns unbound functions
* Get-PSReadlineKeyHandler has 2 new parameters: -Bound and -Unbound
* Set-PSReadlineKeyHandler parameter -LongDescription is now -Description
(not breaking because I left an alias)
* WhatIsKey - display binding for a key
* ShowKeyBindings - show all bound keys
* Keyboard selection of text for cut/copy/delete. New functions:
- Cut
- Copy
- KillRegion
- SelectBackwardChar
- SelectForwardChar
- SelectBackwardWord
- SelectForwardWord
- SelectNextWord
- SelectShellForwardWord
- SelectShellBackwardWord
Breaking change:
* The properties in the output of Get-PSReadlineKeyHandler have changed.
This is unlikely to break anyone though.
### Version 1.0.0.5
New features:
* Delimiter support in *Word functions
* DigitArgument (Alt-0,Alt-1,Alt-2,...,Alt-9,Alt--) to pass numeric arguments
* YankLastArg/YankNthArg to extract arguments from previous command lines
* History search is now case insensitive with an option to make it case sensitive
Bugs fixed:
* Shift+Backspace works like Backspace
* Ctrl+R with long search lines no longer causes big problems
Behavior change:
* Word functions now use delimiters. The previous behavior is available
via a Shell*Word function, e.g. instead of KillWord, use ShellKillWord.
### Version 1.0.0.4
New features:
* Interactive history search (Ctrl+R)
* Brace matching function added (GotoBrace)
* Clear screen (Ctrl+L)
Bugs fixed:
* When showing possible completions, truncate at newline
* Prompt before showing a large number of completions
* Undo after paste works now
* Long pause after clicking on X to close powershell is now fixed
### Version 1.0.0.3
Bugs fixed:
* Removed CLR 4.5 dependency
* Fix bug where console paste didn't display everything in some cases
### Version 1.0.0.2
New features:
* Add a "demo mode" that shows keys pressed
* Add ETW event source for demo mode, key logger, macro recorder etc.
* Undo/redo
* Get-PSReadlineOption cmdlet
* Make specifying key handlers for builtins simpler
* Current un-entered line is saved and recalled when cycling through history
* Support syntax coloring of member names
Bugs fixed:
* Speed up pasting from the console
* Fix coloring of some operators
* Fix coloring in some command arguments
* Ctrl-C is handled a little better
Breaking changes:
* CLR 4.5 is now required.
* SetBufferState is gone because it doesn't support Undo/Redo
### Version 1.0.0.1
New features:
* History imported when module is loaded
* Ctrl+End/Ctrl+Home bindings emulate cmd
* Arbitrary two key chords
* Key handlers passed the invoking key and an optional argument
* Made Ding public for custom handlers
Bugs fixed:
* Alternate keyboards now supported
* Ctrl-C now properly emulates cmd
Breaking changes:
* MinimumHistoryCommandLength parameter removed from Set-PSReadlineOption
- Can use this instead:
Set-PSReadlineOption -AddToHistoryHandler { $args[0].Length -gt 3 }
### Version 1.0.0.0
Initial release

View file

@ -1,812 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Management.Automation;
using System.Management.Automation.Language;
using System.Reflection;
using System.Linq;
namespace Microsoft.PowerShell
{
#pragma warning disable 1591
public enum TokenClassification
{
None,
Comment,
Keyword,
String,
Operator,
Variable,
Command,
Parameter,
Type,
Number,
Member,
}
public enum EditMode
{
Windows,
Emacs,
Vi,
}
public enum BellStyle
{
None,
Visual,
Audible
}
#region vi
public enum ViModeStyle
{
None,
Prompt,
Cursor
}
public enum ViMode
{
Insert,
Command
}
#endregion vi
public enum HistorySaveStyle
{
SaveIncrementally,
SaveAtExit,
SaveNothing
}
public class PSConsoleReadlineOptions
{
#if UNIX // TODO: why different schemes for LINUX?
public const ConsoleColor DefaultCommentForegroundColor = ConsoleColor.Magenta;
public const ConsoleColor DefaultOperatorForegroundColor = ConsoleColor.Gray;
public const ConsoleColor DefaultParameterForegroundColor = ConsoleColor.Green;
#else
public const ConsoleColor DefaultCommentForegroundColor = ConsoleColor.DarkGreen;
public const ConsoleColor DefaultOperatorForegroundColor = ConsoleColor.DarkGray;
public const ConsoleColor DefaultParameterForegroundColor = ConsoleColor.DarkGray;
#endif
public const ConsoleColor DefaultKeywordForegroundColor = ConsoleColor.Green;
public const ConsoleColor DefaultStringForegroundColor = ConsoleColor.DarkCyan;
public const ConsoleColor DefaultVariableForegroundColor = ConsoleColor.Green;
public const ConsoleColor DefaultCommandForegroundColor = ConsoleColor.Yellow;
public const ConsoleColor DefaultTypeForegroundColor = ConsoleColor.Gray;
public const ConsoleColor DefaultNumberForegroundColor = ConsoleColor.White;
public const ConsoleColor DefaultMemberForegroundColor = ConsoleColor.Gray;
public const ConsoleColor DefaultEmphasisForegroundColor = ConsoleColor.Cyan;
public const ConsoleColor DefaultErrorForegroundColor = ConsoleColor.Red;
public const EditMode DefaultEditMode =
#if UNIX
EditMode.Emacs;
#else
EditMode.Windows;
#endif
public const string DefaultContinuationPrompt = ">> ";
/// <summary>
/// The maximum number of commands to store in the history.
/// </summary>
public const int DefaultMaximumHistoryCount = 4096;
/// <summary>
/// The maximum number of items to store in the kill ring.
/// </summary>
public const int DefaultMaximumKillRingCount = 10;
/// <summary>
/// In Emacs, when searching history, the cursor doesn't move.
/// In 4NT, the cursor moves to the end. This option allows
/// for either behavior.
/// </summary>
public const bool DefaultHistorySearchCursorMovesToEnd = false;
/// <summary>
/// When displaying possible completions, either display
/// tooltips or display just the completions.
/// </summary>
public const bool DefaultShowToolTips = false;
/// <summary>
/// When ringing the bell, what frequency do we use?
/// </summary>
public const int DefaultDingTone = 1221;
public const int DefaultDingDuration = 50;
public const int DefaultCompletionQueryItems = 100;
// Default includes all characters PowerShell treats like a dash - em dash, en dash, horizontal bar
public const string DefaultWordDelimiters = @";:,.[]{}()/\|^&*-=+'""" + "\u2013\u2014\u2015";
/// <summary>
/// When ringing the bell, what should be done?
/// </summary>
public const BellStyle DefaultBellStyle = BellStyle.Audible;
public const bool DefaultHistorySearchCaseSensitive = false;
public const HistorySaveStyle DefaultHistorySaveStyle = HistorySaveStyle.SaveIncrementally;
public PSConsoleReadlineOptions(string hostName)
{
ResetColors();
EditMode = DefaultEditMode;
ContinuationPrompt = DefaultContinuationPrompt;
ContinuationPromptBackgroundColor = Console.BackgroundColor;
ContinuationPromptForegroundColor = Console.ForegroundColor;
ExtraPromptLineCount = DefaultExtraPromptLineCount;
AddToHistoryHandler = null;
HistoryNoDuplicates = DefaultHistoryNoDuplicates;
MaximumHistoryCount = DefaultMaximumHistoryCount;
MaximumKillRingCount = DefaultMaximumKillRingCount;
HistorySearchCursorMovesToEnd = DefaultHistorySearchCursorMovesToEnd;
ShowToolTips = DefaultShowToolTips;
DingDuration = DefaultDingDuration;
DingTone = DefaultDingTone;
BellStyle = DefaultBellStyle;
CompletionQueryItems = DefaultCompletionQueryItems;
WordDelimiters = DefaultWordDelimiters;
HistorySearchCaseSensitive = DefaultHistorySearchCaseSensitive;
HistorySaveStyle = DefaultHistorySaveStyle;
string historyFileName = hostName + "_history.txt";
#if UNIX
// PSReadline does not have access to Utils.CorePSPlatform. Must set PSReadline path separately
string historyPath = System.Environment.GetEnvironmentVariable("XDG_DATA_HOME");
if (!String.IsNullOrEmpty(historyPath))
{
historyPath = System.IO.Path.Combine(historyPath, "powershell", "PSReadLine", historyFileName);
HistorySavePath = historyPath;
}
else
{
// History is data, so it goes into .local/share/powershell folder
HistorySavePath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("HOME"),
".local",
"share",
"powershell",
"PSReadLine",
historyFileName);
}
#else
HistorySavePath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("APPDATA"),
@"Microsoft\Windows\PowerShell\PSReadline\",
historyFileName);
#endif
CommandValidationHandler = null;
CommandsToValidateScriptBlockArguments = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"ForEach-Object", "%",
"Invoke-Command", "icm",
"Measure-Command",
"New-Module", "nmo",
"Register-EngineEvent",
"Register-ObjectEvent",
"Register-WMIEvent",
"Set-PSBreakpoint", "sbp",
"Start-Job", "sajb",
"Trace-Command", "trcm",
"Use-Transaction",
"Where-Object", "?", "where",
};
}
public EditMode EditMode { get; set; }
public string ContinuationPrompt { get; set; }
public ConsoleColor ContinuationPromptForegroundColor { get; set; }
public ConsoleColor ContinuationPromptBackgroundColor { get; set; }
/// <summary>
/// Prompts are typically 1 line, but sometimes they may span lines. This
/// count is used to make sure we can display the full prompt after showing
/// ambiguous completions
/// </summary>
public int ExtraPromptLineCount { get; set; }
public const int DefaultExtraPromptLineCount = 0;
/// <summary>
/// This handler is called before adding a command line to history.
/// The return value indicates if the command line should be added
/// to history or not.
/// </summary>
public Func<string, bool> AddToHistoryHandler { get; set; }
/// <summary>
/// This handler is called from ValidateAndAcceptLine.
/// If an exception is thrown, validation fails and the error is reported.
/// </summary>
public Action<CommandAst> CommandValidationHandler { get; set; }
/// <summary>
/// Most commands do not accept script blocks, but for those that do,
/// we want to validate commands in the script block arguments.
/// Unfortunately, we can't know how the argument is used. In the worst
/// case, for commands like Get-ADUser, the script block actually
/// specifies a different language.
///
/// Because we can't know ahead of time all of the commands that do
/// odd things with script blocks, we create a white-list of commands
/// that do invoke the script block - this covers the most useful cases.
/// </summary>
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public HashSet<string> CommandsToValidateScriptBlockArguments { get; set; }
/// <summary>
/// When true, duplicates will not be added to the history.
/// </summary>
public bool HistoryNoDuplicates { get; set; }
public const bool DefaultHistoryNoDuplicates = false;
public int MaximumHistoryCount { get; set; }
public int MaximumKillRingCount { get; set; }
public bool HistorySearchCursorMovesToEnd { get; set; }
public bool ShowToolTips { get; set; }
public int DingTone { get; set; }
public int CompletionQueryItems { get; set; }
public string WordDelimiters { get; set; }
/// <summary>
/// When ringing the bell, how long (in ms)?
/// </summary>
public int DingDuration { get; set; }
public BellStyle BellStyle { get; set; }
public bool HistorySearchCaseSensitive { get; set; }
internal StringComparison HistoryStringComparison
{
get { return HistorySearchCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase; }
}
#region vi
public ViModeStyle ViModeIndicator { get; set; }
#endregion vi
/// <summary>
/// The path to the saved history.
/// </summary>
public string HistorySavePath { get; set; }
public HistorySaveStyle HistorySaveStyle { get; set; }
public ConsoleColor DefaultTokenForegroundColor { get; set; }
public ConsoleColor CommentForegroundColor { get; set; }
public ConsoleColor KeywordForegroundColor { get; set; }
public ConsoleColor StringForegroundColor { get; set; }
public ConsoleColor OperatorForegroundColor { get; set; }
public ConsoleColor VariableForegroundColor { get; set; }
public ConsoleColor CommandForegroundColor { get; set; }
public ConsoleColor ParameterForegroundColor { get; set; }
public ConsoleColor TypeForegroundColor { get; set; }
public ConsoleColor NumberForegroundColor { get; set; }
public ConsoleColor MemberForegroundColor { get; set; }
public ConsoleColor DefaultTokenBackgroundColor { get; set; }
public ConsoleColor CommentBackgroundColor { get; set; }
public ConsoleColor KeywordBackgroundColor { get; set; }
public ConsoleColor StringBackgroundColor { get; set; }
public ConsoleColor OperatorBackgroundColor { get; set; }
public ConsoleColor VariableBackgroundColor { get; set; }
public ConsoleColor CommandBackgroundColor { get; set; }
public ConsoleColor ParameterBackgroundColor { get; set; }
public ConsoleColor TypeBackgroundColor { get; set; }
public ConsoleColor NumberBackgroundColor { get; set; }
public ConsoleColor MemberBackgroundColor { get; set; }
public ConsoleColor EmphasisForegroundColor { get; set; }
public ConsoleColor EmphasisBackgroundColor { get; set; }
public ConsoleColor ErrorForegroundColor { get; set; }
public ConsoleColor ErrorBackgroundColor { get; set; }
internal void ResetColors()
{
DefaultTokenForegroundColor = Console.ForegroundColor;
CommentForegroundColor = DefaultCommentForegroundColor;
KeywordForegroundColor = DefaultKeywordForegroundColor;
StringForegroundColor = DefaultStringForegroundColor;
OperatorForegroundColor = DefaultOperatorForegroundColor;
VariableForegroundColor = DefaultVariableForegroundColor;
CommandForegroundColor = DefaultCommandForegroundColor;
ParameterForegroundColor = DefaultParameterForegroundColor;
TypeForegroundColor = DefaultTypeForegroundColor;
NumberForegroundColor = DefaultNumberForegroundColor;
MemberForegroundColor = DefaultNumberForegroundColor;
EmphasisForegroundColor = DefaultEmphasisForegroundColor;
ErrorForegroundColor = DefaultErrorForegroundColor;
DefaultTokenBackgroundColor = Console.BackgroundColor;
CommentBackgroundColor = Console.BackgroundColor;
KeywordBackgroundColor = Console.BackgroundColor;
StringBackgroundColor = Console.BackgroundColor;
OperatorBackgroundColor = Console.BackgroundColor;
VariableBackgroundColor = Console.BackgroundColor;
CommandBackgroundColor = Console.BackgroundColor;
ParameterBackgroundColor = Console.BackgroundColor;
TypeBackgroundColor = Console.BackgroundColor;
NumberBackgroundColor = Console.BackgroundColor;
MemberBackgroundColor = Console.BackgroundColor;
EmphasisBackgroundColor = Console.BackgroundColor;
ErrorBackgroundColor = Console.BackgroundColor;
}
internal void SetForegroundColor(TokenClassification tokenKind, ConsoleColor color)
{
switch (tokenKind)
{
case TokenClassification.None: DefaultTokenForegroundColor = color; break;
case TokenClassification.Comment: CommentForegroundColor = color; break;
case TokenClassification.Keyword: KeywordForegroundColor = color; break;
case TokenClassification.String: StringForegroundColor = color; break;
case TokenClassification.Operator: OperatorForegroundColor = color; break;
case TokenClassification.Variable: VariableForegroundColor = color; break;
case TokenClassification.Command: CommandForegroundColor = color; break;
case TokenClassification.Parameter: ParameterForegroundColor = color; break;
case TokenClassification.Type: TypeForegroundColor = color; break;
case TokenClassification.Number: NumberForegroundColor = color; break;
case TokenClassification.Member: MemberForegroundColor = color; break;
}
}
internal void SetBackgroundColor(TokenClassification tokenKind, ConsoleColor color)
{
switch (tokenKind)
{
case TokenClassification.None: DefaultTokenBackgroundColor = color; break;
case TokenClassification.Comment: CommentBackgroundColor = color; break;
case TokenClassification.Keyword: KeywordBackgroundColor = color; break;
case TokenClassification.String: StringBackgroundColor = color; break;
case TokenClassification.Operator: OperatorBackgroundColor = color; break;
case TokenClassification.Variable: VariableBackgroundColor = color; break;
case TokenClassification.Command: CommandBackgroundColor = color; break;
case TokenClassification.Parameter: ParameterBackgroundColor = color; break;
case TokenClassification.Type: TypeBackgroundColor = color; break;
case TokenClassification.Number: NumberBackgroundColor = color; break;
case TokenClassification.Member: MemberBackgroundColor = color; break;
}
}
}
[Cmdlet(VerbsCommon.Get, "PSReadlineOption", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528808")]
[OutputType(typeof(PSConsoleReadlineOptions))]
public class GetPSReadlineOption : PSCmdlet
{
[ExcludeFromCodeCoverage]
protected override void EndProcessing()
{
WriteObject(PSConsoleReadLine.GetOptions());
}
}
[Cmdlet(VerbsCommon.Set, "PSReadlineOption", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528811")]
public class SetPSReadlineOption : PSCmdlet
{
[Parameter(ParameterSetName = "OptionsSet")]
public EditMode EditMode
{
get { return _editMode.GetValueOrDefault(); }
set { _editMode = value; }
}
internal EditMode? _editMode;
[Parameter(ParameterSetName = "OptionsSet")]
[AllowEmptyString]
public string ContinuationPrompt { get; set; }
[Parameter(ParameterSetName = "OptionsSet")]
public ConsoleColor ContinuationPromptForegroundColor
{
get { return _continuationPromptForegroundColor.GetValueOrDefault(); }
set { _continuationPromptForegroundColor = value; }
}
internal ConsoleColor? _continuationPromptForegroundColor;
[Parameter(ParameterSetName = "OptionsSet")]
public ConsoleColor ContinuationPromptBackgroundColor
{
get { return _continuationPromptBackgroundColor.GetValueOrDefault(); }
set { _continuationPromptBackgroundColor = value; }
}
internal ConsoleColor? _continuationPromptBackgroundColor;
[Parameter(ParameterSetName = "OptionsSet")]
public ConsoleColor EmphasisForegroundColor
{
get { return _emphasisForegroundColor.GetValueOrDefault(); }
set { _emphasisForegroundColor = value; }
}
internal ConsoleColor? _emphasisForegroundColor;
[Parameter(ParameterSetName = "OptionsSet")]
public ConsoleColor EmphasisBackgroundColor
{
get { return _emphasisBackgroundColor.GetValueOrDefault(); }
set { _emphasisBackgroundColor = value; }
}
internal ConsoleColor? _emphasisBackgroundColor;
[Parameter(ParameterSetName = "OptionsSet")]
public ConsoleColor ErrorForegroundColor
{
get { return _errorForegroundColor.GetValueOrDefault(); }
set { _errorForegroundColor = value; }
}
internal ConsoleColor? _errorForegroundColor;
[Parameter(ParameterSetName = "OptionsSet")]
public ConsoleColor ErrorBackgroundColor
{
get { return _errorBackgroundColor.GetValueOrDefault(); }
set { _errorBackgroundColor = value; }
}
internal ConsoleColor? _errorBackgroundColor;
[Parameter(ParameterSetName = "OptionsSet")]
public SwitchParameter HistoryNoDuplicates
{
get { return _historyNoDuplicates.GetValueOrDefault(); }
set { _historyNoDuplicates = value; }
}
internal SwitchParameter? _historyNoDuplicates;
[Parameter(ParameterSetName = "OptionsSet")]
[AllowNull]
public Func<string, bool> AddToHistoryHandler
{
get { return _addToHistoryHandler; }
set
{
_addToHistoryHandler = value;
_addToHistoryHandlerSpecified = true;
}
}
private Func<string, bool> _addToHistoryHandler;
internal bool _addToHistoryHandlerSpecified;
[Parameter(ParameterSetName = "OptionsSet")]
[AllowNull]
public Action<CommandAst> CommandValidationHandler
{
get { return _commandValidationHandler; }
set
{
_commandValidationHandler = value;
_commandValidationHandlerSpecified = true;
}
}
private Action<CommandAst> _commandValidationHandler;
internal bool _commandValidationHandlerSpecified;
[Parameter(ParameterSetName = "OptionsSet")]
public SwitchParameter HistorySearchCursorMovesToEnd
{
get { return _historySearchCursorMovesToEnd.GetValueOrDefault(); }
set { _historySearchCursorMovesToEnd = value; }
}
internal SwitchParameter? _historySearchCursorMovesToEnd;
[Parameter(ParameterSetName = "OptionsSet")]
public int MaximumHistoryCount
{
get { return _maximumHistoryCount.GetValueOrDefault(); }
set { _maximumHistoryCount = value; }
}
internal int? _maximumHistoryCount;
[Parameter(ParameterSetName = "OptionsSet")]
public int MaximumKillRingCount
{
get { return _maximumKillRingCount.GetValueOrDefault(); }
set { _maximumKillRingCount = value; }
}
internal int? _maximumKillRingCount;
[Parameter(ParameterSetName = "OptionsSet")]
public SwitchParameter ResetTokenColors
{
get { return _resetTokenColors.GetValueOrDefault(); }
set { _resetTokenColors = value; }
}
internal SwitchParameter? _resetTokenColors;
[Parameter(ParameterSetName = "OptionsSet")]
public SwitchParameter ShowToolTips
{
get { return _showToolTips.GetValueOrDefault(); }
set { _showToolTips = value; }
}
internal SwitchParameter? _showToolTips;
[Parameter(ParameterSetName = "OptionsSet")]
public int ExtraPromptLineCount
{
get { return _extraPromptLineCount.GetValueOrDefault(); }
set { _extraPromptLineCount = value; }
}
internal int? _extraPromptLineCount;
[Parameter(ParameterSetName = "OptionsSet")]
public int DingTone
{
get { return _dingTone.GetValueOrDefault(); }
set { _dingTone = value; }
}
internal int? _dingTone;
[Parameter(ParameterSetName = "OptionsSet")]
public int DingDuration
{
get { return _dingDuration.GetValueOrDefault(); }
set { _dingDuration = value; }
}
internal int? _dingDuration;
[Parameter(ParameterSetName = "OptionsSet")]
public BellStyle BellStyle
{
get { return _bellStyle.GetValueOrDefault(); }
set { _bellStyle = value; }
}
internal BellStyle? _bellStyle;
[Parameter(ParameterSetName = "OptionsSet")]
public int CompletionQueryItems
{
get { return _completionQueryItems.GetValueOrDefault(); }
set { _completionQueryItems = value; }
}
internal int? _completionQueryItems;
[Parameter(ParameterSetName = "OptionsSet")]
public string WordDelimiters { get; set; }
[Parameter(ParameterSetName = "OptionsSet")]
public SwitchParameter HistorySearchCaseSensitive
{
get { return _historySearchCaseSensitive.GetValueOrDefault(); }
set { _historySearchCaseSensitive = value; }
}
internal SwitchParameter? _historySearchCaseSensitive;
[Parameter(ParameterSetName = "OptionsSet")]
public HistorySaveStyle HistorySaveStyle
{
get { return _historySaveStyle.GetValueOrDefault(); }
set { _historySaveStyle = value; }
}
internal HistorySaveStyle? _historySaveStyle;
[Parameter(ParameterSetName = "OptionsSet")]
[ValidateNotNullOrEmpty]
public string HistorySavePath { get; set; }
#region vi
[Parameter(ParameterSetName = "OptionsSet")]
public ViModeStyle ViModeIndicator
{
get { return _viModeIndicator.GetValueOrDefault(); }
set { _viModeIndicator = value; }
}
internal ViModeStyle? _viModeIndicator;
#endregion vi
[Parameter(ParameterSetName = "ColorSet", Position = 0, Mandatory = true)]
public TokenClassification TokenKind
{
get { return _tokenKind.GetValueOrDefault(); }
set { _tokenKind = value; }
}
internal TokenClassification? _tokenKind;
[Parameter(ParameterSetName = "ColorSet", Position = 1)]
public ConsoleColor ForegroundColor
{
get { return _foregroundColor.GetValueOrDefault(); }
set { _foregroundColor = value; }
}
internal ConsoleColor? _foregroundColor;
[Parameter(ParameterSetName = "ColorSet", Position = 2)]
public ConsoleColor BackgroundColor
{
get { return _backgroundColor.GetValueOrDefault(); }
set { _backgroundColor = value; }
}
internal ConsoleColor? _backgroundColor;
[ExcludeFromCodeCoverage]
protected override void EndProcessing()
{
PSConsoleReadLine.SetOptions(this);
}
}
public class ChangePSReadlineKeyHandlerCommandBase : PSCmdlet
{
[Parameter(Position = 0, Mandatory = true)]
[Alias("Key")]
[ValidateNotNullOrEmpty]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public string[] Chord { get; set; }
[Parameter]
public ViMode ViMode { get; set; }
[ExcludeFromCodeCoverage]
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;
}
}
[Cmdlet(VerbsCommon.Set, "PSReadlineKeyHandler", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528810")]
public class SetPSReadlineKeyHandlerCommand : ChangePSReadlineKeyHandlerCommandBase, IDynamicParameters
{
[Parameter(Position = 1, Mandatory = true, ParameterSetName = "ScriptBlock")]
[ValidateNotNull]
public ScriptBlock ScriptBlock { get; set; }
[Parameter(ParameterSetName = "ScriptBlock")]
public string BriefDescription { get; set; }
[Parameter(ParameterSetName = "ScriptBlock")]
[Alias("LongDescription")] // Alias to stay comptible with previous releases
public string Description { get; set; }
private const string FunctionParameter = "Function";
private const string FunctionParameterSet = "Function";
[ExcludeFromCodeCoverage]
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);
}
}
}
private readonly Lazy<RuntimeDefinedParameterDictionary> _dynamicParameters =
new Lazy<RuntimeDefinedParameterDictionary>(CreateDynamicParametersResult);
private static RuntimeDefinedParameterDictionary CreateDynamicParametersResult()
{
var bindableFunctions = (typeof(PSConsoleReadLine).GetMethods(BindingFlags.Public | BindingFlags.Static))
.Where(method =>
{
var parameters = method.GetParameters();
return parameters.Length == 2
&& parameters[0].ParameterType == typeof(ConsoleKeyInfo?)
&& parameters[1].ParameterType == typeof(object);
})
.Select(method => method.Name)
.OrderBy(name => name);
var attributes = new Collection<Attribute>
{
new ParameterAttribute
{
Position = 1,
Mandatory = true,
ParameterSetName = FunctionParameterSet
},
new ValidateSetAttribute(bindableFunctions.ToArray())
};
var parameter = new RuntimeDefinedParameter(FunctionParameter, typeof(string), attributes);
var result = new RuntimeDefinedParameterDictionary {{FunctionParameter, parameter}};
return result;
}
public object GetDynamicParameters()
{
return _dynamicParameters.Value;
}
}
[Cmdlet(VerbsCommon.Get, "PSReadlineKeyHandler", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528807")]
[OutputType(typeof(KeyHandler))]
public class GetKeyHandlerCommand : PSCmdlet
{
[Parameter]
public SwitchParameter Bound
{
get { return _bound.GetValueOrDefault(); }
set { _bound = value; }
}
private SwitchParameter? _bound;
[Parameter]
public SwitchParameter Unbound
{
get { return _unbound.GetValueOrDefault(); }
set { _unbound = value; }
}
private SwitchParameter? _unbound;
[ExcludeFromCodeCoverage]
protected override void EndProcessing()
{
bool bound = true;
bool unbound = true;
if (_bound.HasValue && _unbound.HasValue)
{
bound = _bound.Value.IsPresent;
unbound = _unbound.Value.IsPresent;
}
else if (_bound.HasValue)
{
bound = _bound.Value.IsPresent;
unbound = false;
}
else if (_unbound.HasValue)
{
bound = false;
unbound = _unbound.Value.IsPresent;
}
WriteObject(PSConsoleReadLine.GetKeyHandlers(bound, unbound), true);
}
}
[Cmdlet(VerbsCommon.Remove, "PSReadlineKeyHandler", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=528809")]
public class RemoveKeyHandlerCommand : ChangePSReadlineKeyHandlerCommandBase
{
[ExcludeFromCodeCoverage]
protected override void EndProcessing()
{
using (UseRequestedDispatchTables())
{
PSConsoleReadLine.RemoveKeyHandler(Chord);
}
}
}
#pragma warning restore 1591
}

View file

@ -1,556 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
using Microsoft.PowerShell.Internal;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
// Tab completion state
private int _tabCommandCount;
private CommandCompletion _tabCompletions;
private Runspace _runspace;
// String helper for directory paths
private static string DirectorySeparatorString = System.IO.Path.DirectorySeparatorChar.ToString();
// Stub helper method so completion can be mocked
[ExcludeFromCodeCoverage]
CommandCompletion IPSConsoleReadLineMockableMethods.CompleteInput(string input, int cursorIndex, Hashtable options, System.Management.Automation.PowerShell powershell)
{
return CalloutUsingDefaultConsoleMode(
() => CommandCompletion.CompleteInput(input, cursorIndex, options, powershell));
}
/// <summary>
/// Attempt to complete the text surrounding the cursor with the next
/// available completion.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void TabCompleteNext(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.Complete(forward: true);
}
/// <summary>
/// Attempt to complete the text surrounding the cursor with the previous
/// available completion.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void TabCompletePrevious(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.Complete(forward: false);
}
private static bool IsSingleQuote(char c)
{
return c == '\'' || c == (char)8216 || c == (char)8217 || c == (char)8218;
}
private static bool IsDoubleQuote(char c)
{
return c == '"' || c == (char)8220 || c == (char)8221;
}
private static bool IsQuoted(string s)
{
if (s.Length >= 2)
{
var first = s[0];
var last = s[s.Length - 1];
return ((IsSingleQuote(first) && IsSingleQuote(last))
||
(IsDoubleQuote(first) && IsDoubleQuote(last)));
}
return false;
}
private static string GetUnquotedText(string s, bool consistentQuoting)
{
if (!consistentQuoting && IsQuoted(s))
{
s = s.Substring(1, s.Length - 2);
}
return s;
}
/// <summary>
/// Attempt to perform completion on the text surrounding the cursor.
/// If there are multiple possible completions, the longest unambiguous
/// prefix is used for completion. If trying to complete the longest
/// unambiguous completion, a list of possible completions is displayed.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void Complete(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.CompleteImpl(key, arg, false);
}
/// <summary>
/// Attempt to perform completion on the text surrounding the cursor.
/// If there are multiple possible completions, the longest unambiguous
/// prefix is used for completion. If trying to complete the longest
/// unambiguous completion, a list of possible completions is displayed.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void MenuComplete(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.CompleteImpl(key, arg, true);
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
private void CompleteImpl(ConsoleKeyInfo? key, object arg, bool menuSelect)
{
var completions = GetCompletions();
if (completions == null || completions.CompletionMatches.Count == 0)
return;
if (_tabCommandCount > 0)
{
if (completions.CompletionMatches.Count == 1)
{
Ding();
}
else
{
PossibleCompletionsImpl(completions, menuSelect);
}
return;
}
if (completions.CompletionMatches.Count == 1)
{
// We want to add a backslash for directory completion if possible. This
// is mostly only needed if we have a single completion - if there are multiple
// completions, then we'll be showing the possible completions where it's very
// unlikely that we would add a trailing backslash.
DoReplacementForCompletion(completions.CompletionMatches[0], completions);
return;
}
if (menuSelect)
{
PossibleCompletionsImpl(completions, true);
return;
}
// Find the longest unambiguous prefix. This might be the empty
// string, in which case we don't want to remove any of the users input,
// instead we'll immediately show possible completions.
// For the purposes of unambiguous prefix, we'll ignore quotes if
// some completions aren't quoted.
var firstResult = completions.CompletionMatches[0];
int quotedCompletions = completions.CompletionMatches.Count(match => IsQuoted(match.CompletionText));
bool consistentQuoting =
quotedCompletions == 0 ||
(quotedCompletions == completions.CompletionMatches.Count &&
quotedCompletions == completions.CompletionMatches.Count(
m => m.CompletionText[0] == firstResult.CompletionText[0]));
bool ambiguous = false;
var replacementText = GetUnquotedText(firstResult.CompletionText, consistentQuoting);
foreach (var match in completions.CompletionMatches.Skip(1))
{
var matchText = GetUnquotedText(match.CompletionText, consistentQuoting);
for (int i = 0; i < replacementText.Length; i++)
{
if (i == matchText.Length
|| char.ToLowerInvariant(replacementText[i]) != char.ToLowerInvariant(matchText[i]))
{
ambiguous = true;
replacementText = replacementText.Substring(0, i);
break;
}
}
if (replacementText.Length == 0)
{
break;
}
}
if (replacementText.Length > 0)
{
Replace(completions.ReplacementIndex, completions.ReplacementLength, replacementText);
completions.ReplacementLength = replacementText.Length;
if (ambiguous)
{
Ding();
}
}
else
{
// No common prefix, don't wait for a second tab, just show the possible completions
// right away.
PossibleCompletionsImpl(completions, false);
}
_tabCommandCount += 1;
}
private CommandCompletion GetCompletions()
{
if (_tabCommandCount == 0)
{
try
{
_tabCompletions = null;
// Could use the overload that takes an AST as it's faster (we've already parsed the
// input for coloring) but that overload is a little more complicated in passing in the
// cursor position.
System.Management.Automation.PowerShell ps;
if (!_mockableMethods.RunspaceIsRemote(_runspace))
{
ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace);
}
else
{
ps = System.Management.Automation.PowerShell.Create();
ps.Runspace = _runspace;
}
_tabCompletions = _mockableMethods.CompleteInput(_buffer.ToString(), _current, null, ps);
if (_tabCompletions.CompletionMatches.Count == 0)
return null;
}
catch (Exception)
{
}
}
return _tabCompletions;
}
private void Complete(bool forward)
{
var completions = GetCompletions();
if (completions == null)
return;
completions.CurrentMatchIndex += forward ? 1 : -1;
if (completions.CurrentMatchIndex < 0)
{
completions.CurrentMatchIndex = completions.CompletionMatches.Count - 1;
}
else if (completions.CurrentMatchIndex == completions.CompletionMatches.Count)
{
completions.CurrentMatchIndex = 0;
}
var completionResult = completions.CompletionMatches[completions.CurrentMatchIndex];
DoReplacementForCompletion(completionResult, completions);
_tabCommandCount += 1;
}
private void DoReplacementForCompletion(CompletionResult completionResult, CommandCompletion completions)
{
var replacementText = completionResult.CompletionText;
int cursorAdjustment = 0;
if (completionResult.ResultType == CompletionResultType.ProviderContainer)
{
replacementText = GetReplacementTextForDirectory(replacementText, ref cursorAdjustment);
}
Replace(completions.ReplacementIndex, completions.ReplacementLength, replacementText);
if (cursorAdjustment != 0)
{
_current += cursorAdjustment;
PlaceCursor();
}
completions.ReplacementLength = replacementText.Length;
}
private static string GetReplacementTextForDirectory(string replacementText, ref int cursorAdjustment)
{
if (!replacementText.EndsWith(DirectorySeparatorString , StringComparison.Ordinal))
{
if (replacementText.EndsWith(String.Format("{0}\'", DirectorySeparatorString), StringComparison.Ordinal) ||
replacementText.EndsWith(String.Format("{0}\"", DirectorySeparatorString), StringComparison.Ordinal))
{
cursorAdjustment = -1;
}
else if (replacementText.EndsWith("'", StringComparison.Ordinal) ||
replacementText.EndsWith("\"", StringComparison.Ordinal))
{
var len = replacementText.Length;
replacementText = replacementText.Substring(0, len - 1) + System.IO.Path.DirectorySeparatorChar + replacementText[len - 1];
cursorAdjustment = -1;
}
else
{
replacementText = replacementText + System.IO.Path.DirectorySeparatorChar;
}
}
return replacementText;
}
private static void InvertSelectedCompletion(BufferChar[] buffer, int selectedItem, int menuColumnWidth, int menuRows)
{
var selectedX = selectedItem / menuRows;
var selectedY = selectedItem - (selectedX * menuRows);
var start = selectedY * _singleton._console.BufferWidth + selectedX * menuColumnWidth;
for (int i = 0; i < menuColumnWidth; i++)
{
buffer[i + start].Inverse = true;
}
}
/// <summary>
/// Display the list of possible completions.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void PossibleCompletions(ConsoleKeyInfo? key = null, object arg = null)
{
var completions = _singleton.GetCompletions();
_singleton.PossibleCompletionsImpl(completions, menuSelect: false);
}
private static string HandleNewlinesForPossibleCompletions(string s)
{
s = s.Trim();
var newlineIndex = s.IndexOfAny(new []{'\r', '\n'});
if (newlineIndex >= 0)
{
s = s.Substring(0, newlineIndex) + "...";
}
return s;
}
private void PossibleCompletionsImpl(CommandCompletion completions, bool menuSelect)
{
if (completions == null || completions.CompletionMatches.Count == 0)
{
Ding();
return;
}
if (completions.CompletionMatches.Count >= _options.CompletionQueryItems)
{
if (!PromptYesOrNo(string.Format(CultureInfo.CurrentCulture, PSReadLineResources.DisplayAllPossibilities, completions.CompletionMatches.Count)))
{
return;
}
}
var matches = completions.CompletionMatches;
var minColWidth = matches.Max(c => c.ListItemText.Length);
minColWidth += 2;
var menuColumnWidth = minColWidth;
int displayRows;
var bufferWidth = _console.BufferWidth;
ConsoleBufferBuilder cb;
if (Options.ShowToolTips)
{
const string seperator = "- ";
var maxTooltipWidth = bufferWidth - minColWidth - seperator.Length;
displayRows = matches.Count;
cb = new ConsoleBufferBuilder(displayRows * bufferWidth, _console);
for (int index = 0; index < matches.Count; index++)
{
var match = matches[index];
var listItemText = HandleNewlinesForPossibleCompletions(match.ListItemText);
cb.Append(listItemText);
var spacesNeeded = minColWidth - listItemText.Length;
if (spacesNeeded > 0)
{
cb.Append(' ', spacesNeeded);
}
cb.Append(seperator);
var toolTip = HandleNewlinesForPossibleCompletions(match.ToolTip);
toolTip = toolTip.Length <= maxTooltipWidth
? toolTip
: toolTip.Substring(0, maxTooltipWidth);
cb.Append(toolTip);
// Make sure we always write out exactly 1 buffer width
spacesNeeded = (bufferWidth * (index + 1)) - cb.Length;
if (spacesNeeded > 0)
{
cb.Append(' ', spacesNeeded);
}
}
menuColumnWidth = bufferWidth;
}
else
{
var screenColumns = bufferWidth;
var displayColumns = Math.Max(1, screenColumns / minColWidth);
displayRows = (completions.CompletionMatches.Count + displayColumns - 1) / displayColumns;
cb = new ConsoleBufferBuilder(displayRows * bufferWidth, _console);
for (var row = 0; row < displayRows; row++)
{
for (var col = 0; col < displayColumns; col++)
{
var index = row + (displayRows * col);
if (index >= matches.Count)
break;
var match = matches[index];
var item = HandleNewlinesForPossibleCompletions(match.ListItemText);
cb.Append(item);
cb.Append(' ', minColWidth - item.Length);
}
// Make sure we always write out exactly 1 buffer width
var spacesNeeded = (bufferWidth * (row + 1)) - cb.Length;
if (spacesNeeded > 0)
{
cb.Append(' ', spacesNeeded);
}
}
}
var menuBuffer = cb.ToArray();
if (menuSelect)
{
// Make sure the menu and line can appear on the screen at the same time,
// if not, we'll skip the menu.
var endBufferCoords = ConvertOffsetToCoordinates(_buffer.Length);
var bufferLines = endBufferCoords.Y - _initialY + 1;
if ((bufferLines + displayRows) > _console.WindowHeight)
{
menuSelect = false;
}
}
if (menuSelect)
{
RemoveEditsAfterUndo();
var undoPoint = _edits.Count;
int selectedItem = 0;
bool undo = false;
DoReplacementForCompletion(matches[0], completions);
// Recompute end of buffer coordinates as the replacement could have
// added a line.
var endBufferCoords = ConvertOffsetToCoordinates(_buffer.Length);
var menuAreaTop = endBufferCoords.Y + 1;
var previousMenuTop = menuAreaTop;
InvertSelectedCompletion(menuBuffer, selectedItem, menuColumnWidth, displayRows);
_console.WriteBufferLines(menuBuffer, ref menuAreaTop);
// Showing the menu may have scrolled the screen or moved the cursor, update initialY to reflect that.
_initialY -= (previousMenuTop - menuAreaTop);
PlaceCursor();
previousMenuTop = menuAreaTop;
int previousItem = selectedItem;
bool processingKeys = true;
while (processingKeys)
{
var nextKey = ReadKey();
if (nextKey == Keys.RightArrow)
{
selectedItem = Math.Min(selectedItem + displayRows, matches.Count - 1);
}
else if (nextKey == Keys.LeftArrow)
{
selectedItem = Math.Max(selectedItem - displayRows, 0);
}
else if (nextKey == Keys.DownArrow)
{
selectedItem = Math.Min(selectedItem + 1, matches.Count - 1);
}
else if (nextKey == Keys.UpArrow)
{
selectedItem = Math.Max(selectedItem - 1, 0);
}
else if (nextKey == Keys.Tab)
{
selectedItem = (selectedItem + 1) % matches.Count;
}
else if (nextKey == Keys.ShiftTab)
{
selectedItem = (selectedItem - 1) % matches.Count;
if (selectedItem < 0)
{
selectedItem += matches.Count;
}
}
else if (nextKey == Keys.CtrlG || nextKey == Keys.Escape)
{
undo = true;
processingKeys = false;
}
else
{
PrependQueuedKeys(nextKey);
processingKeys = false;
}
if (selectedItem != previousItem)
{
DoReplacementForCompletion(matches[selectedItem], completions);
endBufferCoords = ConvertOffsetToCoordinates(_buffer.Length);
menuAreaTop = endBufferCoords.Y + 1;
InvertSelectedCompletion(menuBuffer, previousItem, menuColumnWidth, displayRows);
InvertSelectedCompletion(menuBuffer, selectedItem, menuColumnWidth, displayRows);
_console.WriteBufferLines(menuBuffer, ref menuAreaTop);
previousItem = selectedItem;
if (previousMenuTop > menuAreaTop)
{
WriteBlankLines(previousMenuTop - menuAreaTop, menuAreaTop + displayRows);
}
}
}
WriteBlankLines(displayRows, menuAreaTop);
var lastInsert = ((GroupedEdit)_edits[_edits.Count - 1])._groupedEditItems[1];
Debug.Assert(lastInsert is EditItemInsertString, "The only edits possible here are pairs of Delete/Insert");
var firstDelete = ((GroupedEdit)_edits[undoPoint])._groupedEditItems[0];
Debug.Assert(firstDelete is EditItemDelete, "The only edits possible here are pairs of Delete/Insert");
var groupEditCount = _edits.Count - undoPoint;
_edits.RemoveRange(undoPoint, groupEditCount);
_undoEditIndex = undoPoint;
if (undo)
{
// Pretend it never happened.
lastInsert.Undo();
firstDelete.Undo();
Render();
}
else
{
// Leave one edit instead of possibly many to undo
SaveEditItem(GroupedEdit.Create(new List<EditItem> { firstDelete, lastInsert }));
}
}
else
{
var endBufferCoords = ConvertOffsetToCoordinates(_buffer.Length);
var menuAreaTop = endBufferCoords.Y + 1;
_console.WriteBufferLines(menuBuffer, ref menuAreaTop);
_initialY = menuAreaTop + displayRows;
Render();
}
}
}
}

View file

@ -1,43 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
/// <summary>
/// Ends the current edit group, if needed, and invokes TabCompleteNext.
/// </summary>
public static void ViTabCompleteNext(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton._editGroupStart >= 0)
{
_singleton._groupUndoHelper.EndGroup();
}
TabCompleteNext(key, arg);
}
/// <summary>
/// Ends the current edit group, if needed, and invokes TabCompletePrevious.
/// </summary>
public static void ViTabCompletePrevious(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton._editGroupStart >= 0)
{
_singleton._groupUndoHelper.EndGroup();
}
TabCompletePrevious(key, arg);
}
}
}

View file

@ -1,59 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using Microsoft.PowerShell.Internal;
namespace Microsoft.PowerShell
{
internal class ConsoleBufferBuilder
{
private List<BufferChar> buffer;
private IConsole _console;
public ConsoleBufferBuilder(int capacity, IConsole console)
{
buffer = new List<BufferChar>(capacity);
_console = console;
}
BufferChar NewCharInfo(char c)
{
return new BufferChar
{
UnicodeChar = c,
BackgroundColor = _console.BackgroundColor,
ForegroundColor = _console.ForegroundColor
};
}
public void Append(string s)
{
foreach (char c in s)
{
buffer.Add(NewCharInfo(c));
}
}
public void Append(char c, int count)
{
while (count-- > 0)
{
buffer.Add(NewCharInfo(c));
}
}
public BufferChar[] ToArray()
{
return buffer.ToArray();
}
public int Length
{
get { return buffer.Count; }
}
}
}

View file

@ -1,341 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.PowerShell.Internal;
namespace Microsoft.PowerShell
{
/// <summary>
/// A helper class for converting strings to ConsoleKey chords.
/// </summary>
public static class ConsoleKeyChordConverter
{
/// <summary>
/// Converts a string to a sequence of ConsoleKeyInfo.
/// Sequences are separated by ','. Modifiers
/// appear before the modified key and are separated by '+'.
/// Examples:
/// Ctrl+X
/// Ctrl+D,M
/// Escape,X
/// </summary>
public static ConsoleKeyInfo[] Convert(string chord)
{
if (string.IsNullOrEmpty(chord))
{
throw new ArgumentNullException("chord");
}
var tokens = chord.Split(new[] {','});
if (tokens.Length > 2)
{
throw new ArgumentException(PSReadLineResources.ChordWithTooManyKeys);
}
var result = new ConsoleKeyInfo[tokens.Length];
for (int i = 0; i < tokens.Length; i++)
{
result[i] = ConvertOneSequence(tokens[i]);
}
return result;
}
private static ConsoleKeyInfo ConvertOneSequence(string sequence)
{
Stack<string> tokens = null;
ConsoleModifiers modifiers = 0;
ConsoleKey key = 0;
char keyChar = '\u0000';
bool valid = !String.IsNullOrEmpty(sequence);
if (valid)
{
tokens = new Stack<string>(
(sequence.Split(new[] {'+'})
.Select(
part => part.ToLowerInvariant().Trim())));
}
while (valid && tokens.Count > 0)
{
string token = tokens.Pop();
// sequence was something silly like "shift++"
if (token == String.Empty)
{
valid = false;
break;
}
// key should be first token to be popped
if (key == 0)
{
// the keyChar is this token, if not a special key like "Fxx" etc.
if (token.Length == 1)
{
keyChar = token[0];
}
// Enum.TryParse accepts arbitrary integers. We shouldn't,
// but single digits need to map to the correct key, e.g.
// ConsoleKey.D1
long tokenAsLong;
if (long.TryParse(token, out tokenAsLong))
{
if (tokenAsLong >= 0 && tokenAsLong <= 9)
{
token = "D" + token;
}
else
{
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, PSReadLineResources.UnrecognizedKey, token));
}
}
// try simple parse for ConsoleKey enum name
valid = Enum.TryParse(token, ignoreCase: true, result: out key);
// doesn't map to ConsoleKey so convert to virtual key from char
if (!valid && token.Length == 1)
{
string failReason;
valid = TryParseCharLiteral(token[0], ref modifiers, ref key, out failReason);
if (!valid)
{
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, PSReadLineResources.CantTranslateKey, token[0], failReason));
}
}
if (!valid)
{
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, PSReadLineResources.UnrecognizedKey, token));
}
}
else
{
// now, parse modifier(s)
ConsoleModifiers modifier;
// courtesy translation
if (token == "ctrl")
{
token = "control";
}
if (Enum.TryParse(token, ignoreCase: true, result: out modifier))
{
// modifier already set?
if ((modifiers & modifier) != 0)
{
// either found duplicate modifier token or shift state
// was already implied from char, e.g. char is "}", which is "shift+]"
throw new ArgumentException(
String.Format(CultureInfo.CurrentCulture, PSReadLineResources.InvalidModifier, modifier, key));
}
modifiers |= modifier;
}
else
{
throw new ArgumentException(
String.Format(CultureInfo.CurrentCulture, PSReadLineResources.InvalidModifier, token, key));
}
}
}
if (!valid)
{
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, PSReadLineResources.InvalidSequence, sequence));
}
return new ConsoleKeyInfo(keyChar, key,
shift: ((modifiers & ConsoleModifiers.Shift) != 0),
alt: ((modifiers & ConsoleModifiers.Alt) != 0),
control: ((modifiers & ConsoleModifiers.Control) != 0));
}
private static bool TryParseCharLiteral(char literal, ref ConsoleModifiers modifiers, ref ConsoleKey key, out string failReason)
{
bool valid = false;
#if UNIX
bool isShift;
bool isCtrl;
key = GetKeyFromCharValue(literal, out isShift, out isCtrl);
// Failure to get a key for the char just means that the key is not
// special (in the ConsoleKey enum), so we return a default key.
// Thus this never fails.
valid = true;
failReason = null;
if (isShift)
{
modifiers |= ConsoleModifiers.Shift;
}
if (isCtrl)
{
modifiers |= ConsoleModifiers.Control;
}
// alt is not possible to get
#else
// shift state will be in MSB
short virtualKey = NativeMethods.VkKeyScan(literal);
int hresult = Marshal.GetLastWin32Error();
if (virtualKey != 0)
{
// e.g. "}" = 0x01dd but "]" is 0x00dd, ergo } = shift+].
// shift = 1, control = 2, alt = 4, hankaku = 8 (ignored)
int state = virtualKey >> 8;
if ((state & 1) == 1)
{
modifiers |= ConsoleModifiers.Shift;
}
if ((state & 2) == 2)
{
modifiers |= ConsoleModifiers.Control;
}
if ((state & 4) == 4)
{
modifiers |= ConsoleModifiers.Alt;
}
virtualKey &= 0xff;
if (Enum.IsDefined(typeof (ConsoleKey), (int) virtualKey))
{
failReason = null;
key = (ConsoleKey) virtualKey;
valid = true;
}
else
{
// haven't seen this happen yet, but possible
failReason = String.Format(CultureInfo.CurrentCulture, PSReadLineResources.UnrecognizedKey, virtualKey);
}
}
else
{
Exception e = Marshal.GetExceptionForHR(hresult);
failReason = e.Message;
}
#endif
return valid;
}
// this is borrowed from the CoreFX internal System.IO.StdInReader class
// https://github.com/dotnet/corefx/blob/5b2ae6aa485773cd5569f56f446698633c9ad945/src/System.Console/src/System/IO/StdInReader.cs#L222
private static ConsoleKey GetKeyFromCharValue(char x, out bool isShift, out bool isCtrl)
{
isShift = false;
isCtrl = false;
switch (x)
{
case '\b':
return ConsoleKey.Backspace;
case '\t':
return ConsoleKey.Tab;
case '\n':
return ConsoleKey.Enter;
case (char)(0x1B):
return ConsoleKey.Escape;
case '*':
return ConsoleKey.Multiply;
case '+':
return ConsoleKey.Add;
case '-':
return ConsoleKey.Subtract;
case '/':
return ConsoleKey.Divide;
case (char)(0x7F):
return ConsoleKey.Delete;
case ' ':
return ConsoleKey.Spacebar;
default:
// 1. Ctrl A to Ctrl Z.
if (x >= 1 && x <= 26)
{
isCtrl = true;
return ConsoleKey.A + x - 1;
}
// 2. Numbers from 0 to 9.
if (x >= '0' && x <= '9')
{
return ConsoleKey.D0 + x - '0';
}
//3. A to Z
if (x >= 'A' && x <= 'Z')
{
isShift = true;
return ConsoleKey.A + (x - 'A');
}
// 4. a to z.
if (x >= 'a' && x <= 'z')
{
return ConsoleKey.A + (x - 'a');
}
break;
}
return default(ConsoleKey);
}
#if !UNIX
internal static char GetCharFromConsoleKey(ConsoleKey key, ConsoleModifiers modifiers)
{
// default for unprintables and unhandled
char keyChar = '\u0000';
// emulate GetKeyboardState bitmap - set high order bit for relevant modifier virtual keys
var state = new byte[256];
state[NativeMethods.VK_SHIFT] = (byte)(((modifiers & ConsoleModifiers.Shift) != 0) ? 0x80 : 0);
state[NativeMethods.VK_CONTROL] = (byte)(((modifiers & ConsoleModifiers.Control) != 0) ? 0x80 : 0);
state[NativeMethods.VK_ALT] = (byte)(((modifiers & ConsoleModifiers.Alt) != 0) ? 0x80 : 0);
// a ConsoleKey enum's value is a virtual key code
uint virtualKey = (uint)key;
// get corresponding scan code
uint scanCode = NativeMethods.MapVirtualKey(virtualKey, NativeMethods.MAPVK_VK_TO_VSC);
// get corresponding character - may be 0, 1 or 2 in length (diacritics)
var chars = new char[2];
int charCount = NativeMethods.ToUnicode(
virtualKey, scanCode, state, chars, chars.Length, NativeMethods.MENU_IS_INACTIVE);
// TODO: support diacritics (charCount == 2)
if (charCount == 1)
{
keyChar = chars[0];
}
return keyChar;
}
#endif
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,27 +0,0 @@
using System;
namespace Microsoft.PowerShell
{
internal sealed class Disposable : IDisposable
{
private Action m_onDispose;
public Disposable(Action onDispose)
{
if (onDispose == null)
throw new ArgumentNullException("onDispose");
m_onDispose = onDispose;
}
public void Dispose()
{
if (m_onDispose != null)
{
m_onDispose();
m_onDispose = null;
}
}
}
}

View file

@ -1,752 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
[DebuggerDisplay("{_line}")]
class HistoryItem
{
public string _line;
public List<EditItem> _edits;
public int _undoEditIndex;
public bool _saved;
public bool _fromDifferentLiveSession;
}
// History state
private HistoryQueue<HistoryItem> _history;
private Dictionary<string, int> _hashedHistory;
private int _currentHistoryIndex;
private int _getNextHistoryIndex;
private int _searchHistoryCommandCount;
private int _recallHistoryCommandCount;
private string _searchHistoryPrefix;
// When cycling through history, the current line (not yet added to history)
// is saved here so it can be restored.
private readonly HistoryItem _savedCurrentLine;
private Mutex _historyFileMutex;
private long _historyFileLastSavedSize;
private const string _forwardISearchPrompt = "fwd-i-search: ";
private const string _backwardISearchPrompt = "bck-i-search: ";
private const string _failedForwardISearchPrompt = "failed-fwd-i-search: ";
private const string _failedBackwardISearchPrompt = "failed-bck-i-search: ";
private string MaybeAddToHistory(string result, List<EditItem> edits, int undoEditIndex, bool readingHistoryFile, bool fromDifferentSession)
{
bool addToHistory = !string.IsNullOrWhiteSpace(result) && ((Options.AddToHistoryHandler == null) || Options.AddToHistoryHandler(result));
if (addToHistory)
{
_history.Enqueue(new HistoryItem
{
_line = result,
_edits = edits,
_undoEditIndex = undoEditIndex,
_saved = readingHistoryFile,
_fromDifferentLiveSession = fromDifferentSession,
});
_currentHistoryIndex = _history.Count;
if (_options.HistorySaveStyle == HistorySaveStyle.SaveIncrementally && !readingHistoryFile)
{
IncrementalHistoryWrite();
}
}
// Clear the saved line unless we used AcceptAndGetNext in which
// case we're really still in middle of history and might want
// to recall the saved line.
if (_getNextHistoryIndex == 0)
{
_savedCurrentLine._line = null;
_savedCurrentLine._edits = null;
_savedCurrentLine._undoEditIndex = 0;
}
return result;
}
private string GetHistorySaveFileMutexName()
{
// Return a reasonably unique name - it's not too important as there will rarely
// be any contention.
return "PSReadlineHistoryFile_" + _options.HistorySavePath.GetHashCode();
}
private void IncrementalHistoryWrite()
{
var i = _currentHistoryIndex - 1;
while (i >= 0)
{
if (_history[i]._saved)
{
break;
}
i -= 1;
}
WriteHistoryRange(i + 1, _history.Count - 1, File.AppendText);
}
private void SaveHistoryAtExit()
{
WriteHistoryRange(0, _history.Count - 1, File.CreateText);
}
private int historyErrorReportedCount;
private void ReportHistoryFileError(Exception e)
{
if (historyErrorReportedCount == 2)
return;
historyErrorReportedCount += 1;
var fgColor = Console.ForegroundColor;
var bgColor = Console.BackgroundColor;
Console.ForegroundColor = Options.ErrorForegroundColor;
Console.WriteLine(PSReadLineResources.HistoryFileErrorMessage, Options.HistorySavePath, e.Message);
if (historyErrorReportedCount == 2)
{
Console.WriteLine(PSReadLineResources.HistoryFileErrorFinalMessage);
}
Console.ForegroundColor = fgColor;
Console.BackgroundColor = bgColor;
}
private bool WithHistoryFileMutexDo(int timeout, Action action)
{
int retryCount = 0;
do
{
try
{
if (_historyFileMutex.WaitOne(timeout))
{
try
{
action();
}
catch (UnauthorizedAccessException uae)
{
ReportHistoryFileError(uae);
return false;
}
catch (IOException ioe)
{
ReportHistoryFileError(ioe);
return false;
}
finally
{
_historyFileMutex.ReleaseMutex();
}
}
}
catch (AbandonedMutexException)
{
retryCount += 1;
}
} while (retryCount > 0 && retryCount < 3);
// No errors to report, so consider it a success even if we timed out on the mutex.
return true;
}
private void WriteHistoryRange(int start, int end, Func<string, StreamWriter> fileOpener)
{
WithHistoryFileMutexDo(100, () =>
{
if (!MaybeReadHistoryFile())
return;
bool retry = true;
retry_after_creating_directory:
try
{
using (var file = fileOpener(Options.HistorySavePath))
{
for (var i = start; i <= end; i++)
{
_history[i]._saved = true;
var line = _history[i]._line.Replace("\n", "`\n");
file.WriteLine(line);
}
}
var fileInfo = new FileInfo(Options.HistorySavePath);
_historyFileLastSavedSize = fileInfo.Length;
}
catch (DirectoryNotFoundException)
{
// Try making the directory, but just once
if (retry)
{
retry = false;
Directory.CreateDirectory(Path.GetDirectoryName(Options.HistorySavePath));
goto retry_after_creating_directory;
}
}
});
}
private bool MaybeReadHistoryFile()
{
if (Options.HistorySaveStyle == HistorySaveStyle.SaveIncrementally)
{
return WithHistoryFileMutexDo(1000, () =>
{
var fileInfo = new FileInfo(Options.HistorySavePath);
if (fileInfo.Exists && fileInfo.Length != _historyFileLastSavedSize)
{
var historyLines = new List<string>();
using (var fs = new FileStream(Options.HistorySavePath, FileMode.Open))
using (var sr = new StreamReader(fs))
{
fs.Seek(_historyFileLastSavedSize, SeekOrigin.Begin);
while (!sr.EndOfStream)
{
historyLines.Add(sr.ReadLine());
}
}
UpdateHistoryFromFile(historyLines, fromDifferentSession: true);
_historyFileLastSavedSize = fileInfo.Length;
}
});
}
// true means no errors, not that we actually read the file
return true;
}
private void ReadHistoryFile()
{
WithHistoryFileMutexDo(1000, () =>
{
if (!File.Exists(Options.HistorySavePath))
{
return;
}
var historyLines = File.ReadAllLines(Options.HistorySavePath);
UpdateHistoryFromFile(historyLines, fromDifferentSession: false);
var fileInfo = new FileInfo(Options.HistorySavePath);
_historyFileLastSavedSize = fileInfo.Length;
});
}
void UpdateHistoryFromFile(IEnumerable<string> historyLines, bool fromDifferentSession)
{
var sb = new StringBuilder();
foreach (var line in historyLines)
{
if (line.EndsWith("`", StringComparison.Ordinal))
{
sb.Append(line, 0, line.Length - 1);
sb.Append('\n');
}
else if (sb.Length > 0)
{
sb.Append(line);
var l = sb.ToString();
var editItems = new List<EditItem> {EditItemInsertString.Create(l, 0)};
MaybeAddToHistory(l, editItems, 1, /*readingHistoryFile*/ true, fromDifferentSession);
sb.Clear();
}
else
{
var editItems = new List<EditItem> {EditItemInsertString.Create(line, 0)};
MaybeAddToHistory(line, editItems, 1, /*readingHistoryFile*/ true, fromDifferentSession);
}
}
}
/// <summary>
/// Add a command to the history - typically used to restore
/// history from a previous session.
/// </summary>
public static void AddToHistory(string command)
{
command = command.Replace("\r\n", "\n");
var editItems = new List<EditItem> {EditItemInsertString.Create(command, 0)};
_singleton.MaybeAddToHistory(command, editItems, 1, readingHistoryFile: false, fromDifferentSession: false);
}
/// <summary>
/// Clears history in PSReadline. This does not affect PowerShell history.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ClearHistory(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton._history != null)
{
_singleton._history.Clear();
}
_singleton._currentHistoryIndex = 0;
}
private void UpdateFromHistory(bool moveCursor)
{
string line;
if (_currentHistoryIndex == _history.Count)
{
line = _savedCurrentLine._line;
_edits = _savedCurrentLine._edits;
_undoEditIndex = _savedCurrentLine._undoEditIndex;
}
else
{
line = _history[_currentHistoryIndex]._line;
_edits = new List<EditItem>(_history[_currentHistoryIndex]._edits);
_undoEditIndex = _history[_currentHistoryIndex]._undoEditIndex;
}
_buffer.Clear();
_buffer.Append(line);
if (moveCursor)
{
_current = _options.EditMode == EditMode.Vi ? 0 : Math.Max(0, _buffer.Length + ViEndOfLineFactor);
}
else if (_current > _buffer.Length)
{
_current = Math.Max(0, _buffer.Length + ViEndOfLineFactor);
}
Render();
}
private void SaveCurrentLine()
{
// We're called before any history operation - so it's convenient
// to check if we need to load history from another sessions now.
MaybeReadHistoryFile();
if (_savedCurrentLine._line == null)
{
_savedCurrentLine._line = _buffer.ToString();
_savedCurrentLine._edits = _edits;
_savedCurrentLine._undoEditIndex = _undoEditIndex;
}
}
private void HistoryRecall(int direction)
{
if (_recallHistoryCommandCount == 0 && LineIsMultiLine())
{
MoveToLine(direction);
return;
}
if (Options.HistoryNoDuplicates && _recallHistoryCommandCount == 0)
{
_hashedHistory = new Dictionary<string, int>();
}
int count = Math.Abs(direction);
direction = direction < 0 ? -1 : +1;
int newHistoryIndex = _currentHistoryIndex;
while (count > 0)
{
newHistoryIndex += direction;
if (newHistoryIndex < 0 || newHistoryIndex >= _history.Count)
{
break;
}
if (_history[newHistoryIndex]._fromDifferentLiveSession)
{
continue;
}
if (Options.HistoryNoDuplicates)
{
var line = _history[newHistoryIndex]._line;
int index;
if (!_hashedHistory.TryGetValue(line, out index))
{
_hashedHistory.Add(line, newHistoryIndex);
--count;
}
else if (newHistoryIndex == index)
{
--count;
}
}
else
{
--count;
}
}
_recallHistoryCommandCount += 1;
if (newHistoryIndex >= 0 && newHistoryIndex <= _history.Count)
{
_currentHistoryIndex = newHistoryIndex;
UpdateFromHistory(moveCursor: true);
}
}
/// <summary>
/// Replace the current input with the 'previous' item from PSReadline history.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void PreviousHistory(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
TryGetArgAsInt(arg, out numericArg, -1);
if (numericArg > 0)
{
numericArg = -numericArg;
}
_singleton.SaveCurrentLine();
_singleton.HistoryRecall(numericArg);
}
/// <summary>
/// Replace the current input with the 'next' item from PSReadline history.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void NextHistory(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
TryGetArgAsInt(arg, out numericArg, +1);
_singleton.SaveCurrentLine();
_singleton.HistoryRecall(numericArg);
}
private void HistorySearch(int direction)
{
if (_searchHistoryCommandCount == 0)
{
if (LineIsMultiLine())
{
MoveToLine(direction);
return;
}
_searchHistoryPrefix = _buffer.ToString(0, _current);
_emphasisStart = 0;
_emphasisLength = _current;
if (Options.HistoryNoDuplicates)
{
_hashedHistory = new Dictionary<string, int>();
}
}
_searchHistoryCommandCount += 1;
int count = Math.Abs(direction);
direction = direction < 0 ? -1 : +1;
int newHistoryIndex = _currentHistoryIndex;
while (count > 0)
{
newHistoryIndex += direction;
if (newHistoryIndex < 0 || newHistoryIndex >= _history.Count)
{
break;
}
if (_history[newHistoryIndex]._fromDifferentLiveSession && _searchHistoryPrefix.Length == 0)
{
continue;
}
var line = newHistoryIndex == _history.Count ? _savedCurrentLine._line : _history[newHistoryIndex]._line;
if (line.StartsWith(_searchHistoryPrefix, Options.HistoryStringComparison))
{
if (Options.HistoryNoDuplicates)
{
int index;
if (!_hashedHistory.TryGetValue(line, out index))
{
_hashedHistory.Add(line, newHistoryIndex);
--count;
}
else if (index == newHistoryIndex)
{
--count;
}
}
else
{
--count;
}
}
}
if (newHistoryIndex >= 0 && newHistoryIndex <= _history.Count)
{
_currentHistoryIndex = newHistoryIndex;
UpdateFromHistory(moveCursor: true);
}
}
/// <summary>
/// Move to the first item in the history.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void BeginningOfHistory(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.SaveCurrentLine();
_singleton._currentHistoryIndex = 0;
_singleton.UpdateFromHistory(moveCursor: true);
}
/// <summary>
/// Move to the last item (the current input) in the history.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void EndOfHistory(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton._currentHistoryIndex = _singleton._history.Count;
_singleton.UpdateFromHistory(moveCursor: true);
}
/// <summary>
/// Replace the current input with the 'previous' item from PSReadline history
/// that matches the characters between the start and the input and the cursor.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void HistorySearchBackward(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
TryGetArgAsInt(arg, out numericArg, -1);
if (numericArg > 0)
{
numericArg = -numericArg;
}
_singleton.SaveCurrentLine();
_singleton.HistorySearch(numericArg);
}
/// <summary>
/// Replace the current input with the 'next' item from PSReadline history
/// that matches the characters between the start and the input and the cursor.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void HistorySearchForward(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
TryGetArgAsInt(arg, out numericArg, +1);
_singleton.SaveCurrentLine();
_singleton.HistorySearch(numericArg);
}
private void UpdateHistoryDuringInteractiveSearch(string toMatch, int direction, ref int searchFromPoint)
{
searchFromPoint += direction;
for (; searchFromPoint >= 0 && searchFromPoint < _history.Count; searchFromPoint += direction)
{
var line = _history[searchFromPoint]._line;
var startIndex = line.IndexOf(toMatch, Options.HistoryStringComparison);
if (startIndex >= 0)
{
if (Options.HistoryNoDuplicates)
{
int index;
if (!_hashedHistory.TryGetValue(line, out index))
{
_hashedHistory.Add(line, searchFromPoint);
}
else if (index != searchFromPoint)
{
continue;
}
}
_statusLinePrompt = direction > 0 ? _forwardISearchPrompt : _backwardISearchPrompt;
_current = startIndex;
_emphasisStart = startIndex;
_emphasisLength = toMatch.Length;
_currentHistoryIndex = searchFromPoint;
UpdateFromHistory(moveCursor: Options.HistorySearchCursorMovesToEnd);
return;
}
}
// Make sure we're never more than 1 away from being in range so if they
// reverse direction, the first time they reverse they are back in range.
if (searchFromPoint < 0)
searchFromPoint = -1;
else if (searchFromPoint >= _history.Count)
searchFromPoint = _history.Count;
_emphasisStart = -1;
_emphasisLength = 0;
_statusLinePrompt = direction > 0 ? _failedForwardISearchPrompt : _failedBackwardISearchPrompt;
Render();
}
private void InteractiveHistorySearchLoop(int direction)
{
var searchFromPoint = _currentHistoryIndex;
var searchPositions = new Stack<int>();
searchPositions.Push(_currentHistoryIndex);
if (Options.HistoryNoDuplicates)
{
_hashedHistory = new Dictionary<string, int>();
}
var toMatch = new StringBuilder(64);
while (true)
{
var key = ReadKey();
KeyHandler handler;
_dispatchTable.TryGetValue(key, out handler);
var function = handler != null ? handler.Action : null;
if (function == ReverseSearchHistory)
{
UpdateHistoryDuringInteractiveSearch(toMatch.ToString(), -1, ref searchFromPoint);
}
else if (function == ForwardSearchHistory)
{
UpdateHistoryDuringInteractiveSearch(toMatch.ToString(), +1, ref searchFromPoint);
}
else if (function == BackwardDeleteChar || key == Keys.Backspace || key == Keys.CtrlH)
{
if (toMatch.Length > 0)
{
toMatch.Remove(toMatch.Length - 1, 1);
_statusBuffer.Remove(_statusBuffer.Length - 2, 1);
searchPositions.Pop();
searchFromPoint = _currentHistoryIndex = searchPositions.Peek();
UpdateFromHistory(moveCursor: Options.HistorySearchCursorMovesToEnd);
if (_hashedHistory != null)
{
// Remove any entries with index < searchFromPoint because
// we are starting the search from this new index - we always
// want to find the latest entry that matches the search string
foreach (var pair in _hashedHistory.ToArray())
{
if (pair.Value < searchFromPoint)
{
_hashedHistory.Remove(pair.Key);
}
}
}
// Prompt may need to have 'failed-' removed.
var toMatchStr = toMatch.ToString();
var startIndex = _buffer.ToString().IndexOf(toMatchStr, Options.HistoryStringComparison);
if (startIndex >= 0)
{
_statusLinePrompt = direction > 0 ? _forwardISearchPrompt : _backwardISearchPrompt;
_current = startIndex;
_emphasisStart = startIndex;
_emphasisLength = toMatch.Length;
Render();
}
}
else
{
Ding();
}
}
else if (key == Keys.Escape)
{
// End search
break;
}
else if (function == Abort)
{
// Abort search
EndOfHistory();
break;
}
else if (EndInteractiveHistorySearch(key, function))
{
PrependQueuedKeys(key);
break;
}
else
{
toMatch.Append(key.KeyChar);
_statusBuffer.Insert(_statusBuffer.Length - 1, key.KeyChar);
var toMatchStr = toMatch.ToString();
var startIndex = _buffer.ToString().IndexOf(toMatchStr, Options.HistoryStringComparison);
if (startIndex < 0)
{
UpdateHistoryDuringInteractiveSearch(toMatchStr, direction, ref searchFromPoint);
}
else
{
_current = startIndex;
_emphasisStart = startIndex;
_emphasisLength = toMatch.Length;
Render();
}
searchPositions.Push(_currentHistoryIndex);
}
}
}
private static bool EndInteractiveHistorySearch(ConsoleKeyInfo key, Action<ConsoleKeyInfo?, object> function)
{
// Keys < ' ' are control characters
if (key.KeyChar < ' ')
{
return true;
}
if ((key.Modifiers & (ConsoleModifiers.Alt | ConsoleModifiers.Control)) != 0)
{
return true;
}
return false;
}
private void InteractiveHistorySearch(int direction)
{
SaveCurrentLine();
// Add a status line that will contain the search prompt and string
_statusLinePrompt = direction > 0 ? _forwardISearchPrompt : _backwardISearchPrompt;
_statusBuffer.Append("_");
Render(); // Render prompt
InteractiveHistorySearchLoop(direction);
_hashedHistory = null;
_currentHistoryIndex = _history.Count;
_emphasisStart = -1;
_emphasisLength = 0;
// Remove our status line, this will render
ClearStatusMessage(render: true);
}
/// <summary>
/// Perform an incremental forward search through history
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ForwardSearchHistory(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.InteractiveHistorySearch(+1);
}
/// <summary>
/// Perform an incremental backward search through history
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ReverseSearchHistory(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.InteractiveHistorySearch(-1);
}
}
}

View file

@ -1,132 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.PowerShell
{
[ExcludeFromCodeCoverage]
internal sealed class QueueDebugView<T>
{
private readonly HistoryQueue<T> _queue;
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items
{
get { return this._queue.ToArray(); }
}
public QueueDebugView(HistoryQueue<T> queue)
{
if (queue == null)
throw new ArgumentNullException("queue");
this._queue = queue;
}
}
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(QueueDebugView<>))]
internal class HistoryQueue<T>
{
private readonly T[] _array;
private int _head;
private int _tail;
public HistoryQueue(int capacity)
{
Debug.Assert(capacity > 0);
_array = new T[capacity];
_head = _tail = Count = 0;
}
public void Clear()
{
for (int i = 0; i < Count; i++)
{
this[i] = default(T);
}
_head = _tail = Count = 0;
}
public bool Contains(T item)
{
return IndexOf(item) != -1;
}
public int Count { get; private set; }
public int IndexOf(T item)
{
// REVIEW: should we use case insensitive here?
var eqComparer = EqualityComparer<T>.Default;
for (int i = 0; i < Count; i++)
{
if (eqComparer.Equals(this[i], item))
{
return i;
}
}
return -1;
}
public void Enqueue(T item)
{
if (Count == _array.Length)
{
Dequeue();
}
_array[_tail] = item;
_tail = (_tail + 1) % _array.Length;
Count += 1;
}
public T Dequeue()
{
Debug.Assert(Count > 0);
T obj = _array[_head];
_array[_head] = default(T);
_head = (_head + 1) % _array.Length;
Count -= 1;
return obj;
}
public T[] ToArray()
{
var result = new T[Count];
if (Count > 0)
{
if (_head < _tail)
{
Array.Copy(_array, _head, result, 0, Count);
}
else
{
Array.Copy(_array, _head, result, 0, _array.Length - _head);
Array.Copy(_array, 0, result, _array.Length - _head, _tail);
}
}
return result;
}
[ExcludeFromCodeCoverage]
public T this[int index]
{
get
{
Debug.Assert(index >= 0 && index < Count);
return _array[(_head + index) % _array.Length];
}
set
{
Debug.Assert(index >= 0 && index < Count);
_array[(_head + index) % _array.Length] = value;
}
}
}
}

View file

@ -1,423 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Management.Automation;
using System.Text;
using Microsoft.PowerShell.Internal;
namespace Microsoft.PowerShell
{
/// <summary>
/// The class is used as the output type for the cmdlet Get-PSReadlineKeyHandler
/// </summary>
public class KeyHandler
{
/// <summary>
/// The key that is bound or unbound.
/// </summary>
public string Key { get; set; }
/// <summary>
/// The name of the function that a key is bound to, if any.
/// </summary>
public string Function { get; set; }
/// <summary>
/// A short description of the behavior of the function.
/// </summary>
public string Description
{
get
{
var result = _description;
if (string.IsNullOrWhiteSpace(result))
result = PSReadLineResources.ResourceManager.GetString(Function + "Description");
if (string.IsNullOrWhiteSpace(result))
result = Function;
return result;
}
set { _description = value; }
}
private string _description;
}
public partial class PSConsoleReadLine
{
class KeyHandler
{
// Each key handler will be passed 2 arguments. Most will ignore these arguments,
// but having a consistent signature greatly simplifies dispatch. Defaults
// should be included on all handlers that ignore their parameters so they
// can be called from PowerShell without passing anything.
//
// The first argument is the key that caused the action to be called
// (the second key when it's a 2 key chord). The default is null (it's nullable)
// because PowerShell can't handle default(ConsoleKeyInfo) as a default.
// Most actions will ignore this argument.
//
// The second argument is an arbitrary object. It will usually be either a number
// (e.g. as a repeat count) or a string. Most actions will ignore this argument.
public Action<ConsoleKeyInfo?, object> Action;
public string BriefDescription;
public string LongDescription
{
get
{
return _longDescription ??
(_longDescription =
PSReadLineResources.ResourceManager.GetString(BriefDescription + "Description"));
}
set { _longDescription = value; }
}
private string _longDescription;
public ScriptBlock ScriptBlock;
}
internal class ConsoleKeyInfoComparer : IEqualityComparer<ConsoleKeyInfo>
{
public bool Equals(ConsoleKeyInfo x, ConsoleKeyInfo y)
{
// We *must not* compare the KeyChar field as its value is platform-dependent.
// We compare exactly the ConsoleKey enum field (which is platform-agnostic)
// and the modifiers.
return x.Key == y.Key && x.Modifiers == y.Modifiers;
}
public int GetHashCode(ConsoleKeyInfo obj)
{
// Because a comparison of two ConsoleKeyInfo objects is a comparison of the
// combination of the ConsoleKey and Modifiers, we must combine their hashes.
// Note that if the ConsoleKey is default, we must fall back to the KeyChar,
// otherwise every non-special key will compare as the same.
int h1 = obj.Key == default(ConsoleKey)
? obj.KeyChar.GetHashCode()
: obj.Key.GetHashCode();
int h2 = obj.Modifiers.GetHashCode();
// This is based on Tuple.GetHashCode
return unchecked(((h1 << 5) + h1) ^ h2);
}
}
static KeyHandler MakeKeyHandler(Action<ConsoleKeyInfo?, object> action, string briefDescription, string longDescription = null, ScriptBlock scriptBlock = null)
{
return new KeyHandler
{
Action = action,
BriefDescription = briefDescription,
LongDescription = longDescription,
ScriptBlock = scriptBlock,
};
}
private Dictionary<ConsoleKeyInfo, KeyHandler> _dispatchTable;
private Dictionary<ConsoleKeyInfo, Dictionary<ConsoleKeyInfo, KeyHandler>> _chordDispatchTable;
/// <summary>
/// Helper to set bindings based on EditMode
/// </summary>
void SetDefaultBindings(EditMode editMode)
{
switch (editMode)
{
case EditMode.Emacs:
SetDefaultEmacsBindings();
break;
case EditMode.Vi:
SetDefaultViBindings();
break;
case EditMode.Windows:
SetDefaultWindowsBindings();
break;
}
}
void SetDefaultWindowsBindings()
{
_dispatchTable = new Dictionary<ConsoleKeyInfo, KeyHandler>(new ConsoleKeyInfoComparer())
{
{ Keys.Enter, MakeKeyHandler(AcceptLine, "AcceptLine") },
{ Keys.ShiftEnter, MakeKeyHandler(AddLine, "AddLine") },
{ Keys.CtrlEnter, MakeKeyHandler(InsertLineAbove, "InsertLineAbove") },
{ Keys.CtrlShiftEnter, MakeKeyHandler(InsertLineBelow, "InsertLineBelow") },
{ Keys.Escape, MakeKeyHandler(RevertLine, "RevertLine") },
{ Keys.LeftArrow, MakeKeyHandler(BackwardChar, "BackwardChar") },
{ Keys.RightArrow, MakeKeyHandler(ForwardChar, "ForwardChar") },
{ Keys.CtrlLeftArrow, MakeKeyHandler(BackwardWord, "BackwardWord") },
{ Keys.CtrlRightArrow, MakeKeyHandler(NextWord, "NextWord") },
{ Keys.ShiftLeftArrow, MakeKeyHandler(SelectBackwardChar, "SelectBackwardChar") },
{ Keys.ShiftRightArrow, MakeKeyHandler(SelectForwardChar, "SelectForwardChar") },
{ Keys.ShiftCtrlLeftArrow, MakeKeyHandler(SelectBackwardWord, "SelectBackwardWord") },
{ Keys.ShiftCtrlRightArrow, MakeKeyHandler(SelectNextWord, "SelectNextWord") },
{ Keys.UpArrow, MakeKeyHandler(PreviousHistory, "PreviousHistory") },
{ Keys.DownArrow, MakeKeyHandler(NextHistory, "NextHistory") },
{ Keys.Home, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") },
{ Keys.End, MakeKeyHandler(EndOfLine, "EndOfLine") },
{ Keys.ShiftHome, MakeKeyHandler(SelectBackwardsLine, "SelectBackwardsLine") },
{ Keys.ShiftEnd, MakeKeyHandler(SelectLine, "SelectLine") },
{ Keys.Delete, MakeKeyHandler(DeleteChar, "DeleteChar") },
{ Keys.Backspace, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") },
{ Keys.CtrlSpace, MakeKeyHandler(MenuComplete, "MenuComplete") },
{ Keys.Tab, MakeKeyHandler(TabCompleteNext, "TabCompleteNext") },
{ Keys.ShiftTab, MakeKeyHandler(TabCompletePrevious, "TabCompletePrevious") },
#if !UNIX
{ Keys.VolumeDown, MakeKeyHandler(Ignore, "Ignore") },
{ Keys.VolumeUp, MakeKeyHandler(Ignore, "Ignore") },
{ Keys.VolumeMute, MakeKeyHandler(Ignore, "Ignore") },
#endif
{ Keys.CtrlA, MakeKeyHandler(SelectAll, "SelectAll") },
{ Keys.CtrlC, MakeKeyHandler(CopyOrCancelLine, "CopyOrCancelLine") },
{ Keys.CtrlShiftC, MakeKeyHandler(Copy, "Copy") },
{ Keys.CtrlL, MakeKeyHandler(ClearScreen, "ClearScreen") },
{ Keys.CtrlR, MakeKeyHandler(ReverseSearchHistory, "ReverseSearchHistory") },
{ Keys.CtrlS, MakeKeyHandler(ForwardSearchHistory, "ForwardSearchHistory") },
{ Keys.CtrlV, MakeKeyHandler(Paste, "Paste") },
{ Keys.CtrlX, MakeKeyHandler(Cut, "Cut") },
{ Keys.CtrlY, MakeKeyHandler(Redo, "Redo") },
{ Keys.CtrlZ, MakeKeyHandler(Undo, "Undo") },
{ Keys.CtrlBackspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") },
{ Keys.CtrlDelete, MakeKeyHandler(KillWord, "KillWord") },
{ Keys.CtrlEnd, MakeKeyHandler(ForwardDeleteLine, "ForwardDeleteLine") },
{ Keys.CtrlHome, MakeKeyHandler(BackwardDeleteLine, "BackwardDeleteLine") },
{ Keys.CtrlRBracket, MakeKeyHandler(GotoBrace, "GotoBrace") },
{ Keys.CtrlAltQuestion, MakeKeyHandler(ShowKeyBindings, "ShowKeyBindings") },
{ Keys.AltPeriod, MakeKeyHandler(YankLastArg, "YankLastArg") },
{ Keys.Alt0, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt1, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt2, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt3, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt4, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt5, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt6, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt7, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt8, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt9, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.AltMinus, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.AltQuestion, MakeKeyHandler(WhatIsKey, "WhatIsKey") },
{ Keys.AltF7, MakeKeyHandler(ClearHistory, "ClearHistory") },
{ Keys.F3, MakeKeyHandler(CharacterSearch, "CharacterSearch") },
{ Keys.ShiftF3, MakeKeyHandler(CharacterSearchBackward, "CharacterSearchBackward") },
{ Keys.F8, MakeKeyHandler(HistorySearchBackward, "HistorySearchBackward") },
{ Keys.ShiftF8, MakeKeyHandler(HistorySearchForward, "HistorySearchForward") },
#if !UNIX
{ Keys.PageUp, MakeKeyHandler(ScrollDisplayUp, "ScrollDisplayUp") },
{ Keys.PageDown, MakeKeyHandler(ScrollDisplayDown, "ScrollDisplayDown") },
{ Keys.CtrlPageUp, MakeKeyHandler(ScrollDisplayUpLine, "ScrollDisplayUpLine") },
{ Keys.CtrlPageDown, MakeKeyHandler(ScrollDisplayDownLine, "ScrollDisplayDownLine") },
#endif
};
_chordDispatchTable = new Dictionary<ConsoleKeyInfo, Dictionary<ConsoleKeyInfo, KeyHandler>>();
}
void SetDefaultEmacsBindings()
{
_dispatchTable = new Dictionary<ConsoleKeyInfo, KeyHandler>(new ConsoleKeyInfoComparer())
{
{ Keys.Backspace, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") },
{ Keys.Enter, MakeKeyHandler(AcceptLine, "AcceptLine") },
{ Keys.ShiftEnter, MakeKeyHandler(AddLine, "AddLine") },
{ Keys.LeftArrow, MakeKeyHandler(BackwardChar, "BackwardChar") },
{ Keys.RightArrow, MakeKeyHandler(ForwardChar, "ForwardChar") },
{ Keys.ShiftLeftArrow, MakeKeyHandler(SelectBackwardChar, "SelectBackwardChar") },
{ Keys.ShiftRightArrow, MakeKeyHandler(SelectForwardChar, "SelectForwardChar") },
{ Keys.UpArrow, MakeKeyHandler(PreviousHistory, "PreviousHistory") },
{ Keys.DownArrow, MakeKeyHandler(NextHistory, "NextHistory") },
{ Keys.AltLess, MakeKeyHandler(BeginningOfHistory, "BeginningOfHistory") },
{ Keys.AltGreater, MakeKeyHandler(EndOfHistory, "EndOfHistory") },
{ Keys.Home, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") },
{ Keys.End, MakeKeyHandler(EndOfLine, "EndOfLine") },
{ Keys.ShiftHome, MakeKeyHandler(SelectBackwardsLine, "SelectBackwardsLine") },
{ Keys.ShiftEnd, MakeKeyHandler(SelectLine, "SelectLine") },
{ Keys.Escape, MakeKeyHandler(Chord, "ChordFirstKey") },
{ Keys.Delete, MakeKeyHandler(DeleteChar, "DeleteChar") },
{ Keys.Tab, MakeKeyHandler(Complete, "Complete") },
{ Keys.CtrlA, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") },
{ Keys.CtrlB, MakeKeyHandler(BackwardChar, "BackwardChar") },
{ Keys.CtrlC, MakeKeyHandler(CopyOrCancelLine, "CopyOrCancelLine") },
{ Keys.CtrlD, MakeKeyHandler(DeleteCharOrExit, "DeleteCharOrExit") },
{ Keys.CtrlE, MakeKeyHandler(EndOfLine, "EndOfLine") },
{ Keys.CtrlF, MakeKeyHandler(ForwardChar, "ForwardChar") },
{ Keys.CtrlG, MakeKeyHandler(Abort, "Abort") },
{ Keys.CtrlH, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") },
{ Keys.CtrlL, MakeKeyHandler(ClearScreen, "ClearScreen") },
{ Keys.CtrlK, MakeKeyHandler(KillLine, "KillLine") },
{ Keys.CtrlM, MakeKeyHandler(ValidateAndAcceptLine,"ValidateAndAcceptLine") },
{ Keys.CtrlN, MakeKeyHandler(NextHistory, "NextHistory") },
{ Keys.CtrlO, MakeKeyHandler(AcceptAndGetNext, "AcceptAndGetNext") },
{ Keys.CtrlP, MakeKeyHandler(PreviousHistory, "PreviousHistory") },
{ Keys.CtrlR, MakeKeyHandler(ReverseSearchHistory, "ReverseSearchHistory") },
{ Keys.CtrlS, MakeKeyHandler(ForwardSearchHistory, "ForwardSearchHistory") },
{ Keys.CtrlU, MakeKeyHandler(BackwardKillLine, "BackwardKillLine") },
{ Keys.CtrlX, MakeKeyHandler(Chord, "ChordFirstKey") },
{ Keys.CtrlW, MakeKeyHandler(UnixWordRubout, "UnixWordRubout") },
{ Keys.CtrlY, MakeKeyHandler(Yank, "Yank") },
{ Keys.CtrlAt, MakeKeyHandler(SetMark, "SetMark") },
{ Keys.CtrlUnderbar, MakeKeyHandler(Undo, "Undo") },
{ Keys.CtrlRBracket, MakeKeyHandler(CharacterSearch, "CharacterSearch") },
{ Keys.AltCtrlRBracket, MakeKeyHandler(CharacterSearchBackward,"CharacterSearchBackward") },
{ Keys.Alt0, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt1, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt2, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt3, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt4, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt5, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt6, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt7, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt8, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Alt9, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.AltMinus, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.AltB, MakeKeyHandler(BackwardWord, "BackwardWord") },
{ Keys.AltShiftB, MakeKeyHandler(SelectBackwardWord, "SelectBackwardWord") },
{ Keys.AltD, MakeKeyHandler(KillWord, "KillWord") },
{ Keys.AltF, MakeKeyHandler(ForwardWord, "ForwardWord") },
{ Keys.AltShiftF, MakeKeyHandler(SelectForwardWord, "SelectForwardWord") },
{ Keys.AltR, MakeKeyHandler(RevertLine, "RevertLine") },
{ Keys.AltY, MakeKeyHandler(YankPop, "YankPop") },
{ Keys.AltBackspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") },
{ Keys.AltEquals, MakeKeyHandler(PossibleCompletions, "PossibleCompletions") },
{ Keys.CtrlSpace, MakeKeyHandler(MenuComplete, "MenuComplete") },
{ Keys.CtrlAltQuestion, MakeKeyHandler(ShowKeyBindings, "ShowKeyBindings") },
{ Keys.AltQuestion, MakeKeyHandler(WhatIsKey, "WhatIsKey") },
{ Keys.AltSpace, MakeKeyHandler(SetMark, "SetMark") }, // useless entry here for completeness - brings up system menu on Windows
{ Keys.AltPeriod, MakeKeyHandler(YankLastArg, "YankLastArg") },
{ Keys.AltUnderbar, MakeKeyHandler(YankLastArg, "YankLastArg") },
{ Keys.AltCtrlY, MakeKeyHandler(YankNthArg, "YankNthArg") },
#if !UNIX
{ Keys.VolumeDown, MakeKeyHandler(Ignore, "Ignore") },
{ Keys.VolumeUp, MakeKeyHandler(Ignore, "Ignore") },
{ Keys.VolumeMute, MakeKeyHandler(Ignore, "Ignore") },
{ Keys.PageUp, MakeKeyHandler(ScrollDisplayUp, "ScrollDisplayUp") },
{ Keys.CtrlPageUp, MakeKeyHandler(ScrollDisplayUpLine, "ScrollDisplayUpLine") },
{ Keys.PageDown, MakeKeyHandler(ScrollDisplayDown, "ScrollDisplayDown") },
{ Keys.CtrlPageDown, MakeKeyHandler(ScrollDisplayDownLine,"ScrollDisplayDownLine") },
{ Keys.CtrlHome, MakeKeyHandler(ScrollDisplayTop, "ScrollDisplayTop") },
{ Keys.CtrlEnd, MakeKeyHandler(ScrollDisplayToCursor,"ScrollDisplayToCursor") },
#endif
};
_chordDispatchTable = new Dictionary<ConsoleKeyInfo, Dictionary<ConsoleKeyInfo, KeyHandler>>();
// Escape,<key> table (meta key)
_chordDispatchTable[Keys.Escape] = new Dictionary<ConsoleKeyInfo, KeyHandler>(new ConsoleKeyInfoComparer())
{
{ Keys.B, MakeKeyHandler(BackwardWord, "BackwardWord") },
{ Keys.D, MakeKeyHandler(KillWord, "KillWord") },
{ Keys.F, MakeKeyHandler(ForwardWord, "ForwardWord") },
{ Keys.R, MakeKeyHandler(RevertLine, "RevertLine") },
{ Keys.Y, MakeKeyHandler(YankPop, "YankPop") },
{ Keys.CtrlY, MakeKeyHandler(YankNthArg, "YankNthArg") },
{ Keys.Backspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") },
{ Keys.Period, MakeKeyHandler(YankLastArg, "YankLastArg") },
{ Keys.Underbar, MakeKeyHandler(YankLastArg, "YankLastArg") },
};
// Ctrl+X,<key> table
_chordDispatchTable[Keys.CtrlX] = new Dictionary<ConsoleKeyInfo, KeyHandler>(new ConsoleKeyInfoComparer())
{
{ Keys.Backspace, MakeKeyHandler(BackwardKillLine, "BackwardKillLine") },
{ Keys.CtrlU, MakeKeyHandler(Undo, "Undo") },
{ Keys.CtrlX, MakeKeyHandler(ExchangePointAndMark, "ExchangePointAndMark") },
};
}
/// <summary>
/// Show all bound keys
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ShowKeyBindings(ConsoleKeyInfo? key = null, object arg = null)
{
var buffer = new StringBuilder();
buffer.AppendFormat(CultureInfo.InvariantCulture, "{0,-20} {1,-24} {2}\n", "Key", "Function", "Description");
buffer.AppendFormat(CultureInfo.InvariantCulture, "{0,-20} {1,-24} {2}\n", "---", "--------", "-----------");
var boundKeys = GetKeyHandlers(includeBound: true, includeUnbound: false);
var console = _singleton._console;
var maxDescriptionLength = console.WindowWidth - 20 - 24 - 2;
foreach (var boundKey in boundKeys)
{
var description = boundKey.Description;
var newline = "\n";
if (description.Length >= maxDescriptionLength)
{
description = description.Substring(0, maxDescriptionLength - 3) + "...";
newline = "";
}
buffer.AppendFormat(CultureInfo.InvariantCulture, "{0,-20} {1,-24} {2}{3}", boundKey.Key, boundKey.Function, description, newline);
}
// Don't overwrite any of the line - so move to first line after the end of our buffer.
var coords = _singleton.ConvertOffsetToCoordinates(_singleton._buffer.Length);
var y = coords.Y + 1;
_singleton.PlaceCursor(0, ref y);
console.WriteLine(buffer.ToString());
_singleton._initialY = console.CursorTop;
_singleton.Render();
}
/// <summary>
/// Read a key and tell me what the key is bound to.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void WhatIsKey(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton._statusLinePrompt = "what-is-key: ";
_singleton.Render();
var toLookup = ReadKey();
KeyHandler keyHandler;
var buffer = new StringBuilder();
_singleton._dispatchTable.TryGetValue(toLookup, out keyHandler);
buffer.Append(toLookup.ToGestureString());
if (keyHandler != null)
{
if (keyHandler.BriefDescription == "ChordFirstKey")
{
Dictionary<ConsoleKeyInfo, KeyHandler> secondKeyDispatchTable;
if (_singleton._chordDispatchTable.TryGetValue(toLookup, out secondKeyDispatchTable))
{
toLookup = ReadKey();
secondKeyDispatchTable.TryGetValue(toLookup, out keyHandler);
buffer.Append(",");
buffer.Append(toLookup.ToGestureString());
}
}
}
buffer.Append(": ");
if (keyHandler != null)
{
buffer.Append(keyHandler.BriefDescription);
if (!string.IsNullOrWhiteSpace(keyHandler.LongDescription))
{
buffer.Append(" - ");
buffer.Append(keyHandler.LongDescription);
}
}
else if (toLookup.KeyChar != 0)
{
buffer.Append("SelfInsert");
buffer.Append(" - ");
buffer.Append(PSReadLineResources.SelfInsertDescription);
}
else
{
buffer.Append(PSReadLineResources.KeyIsUnbound);
}
_singleton.ClearStatusMessage(render: false);
// Don't overwrite any of the line - so move to first line after the end of our buffer.
var coords = _singleton.ConvertOffsetToCoordinates(_singleton._buffer.Length);
var y = coords.Y + 1;
_singleton.PlaceCursor(0, ref y);
_singleton._console.WriteLine(buffer.ToString());
_singleton._initialY = _singleton._console.CursorTop;
_singleton.Render();
}
}
}

View file

@ -1,284 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
internal static ConsoleColor AlternateBackground(ConsoleColor bg)
{
switch (bg)
{
case ConsoleColor.Black: return ConsoleColor.DarkGray;
case ConsoleColor.Blue: return ConsoleColor.DarkBlue;
case ConsoleColor.Cyan: return ConsoleColor.DarkCyan;
case ConsoleColor.DarkBlue: return ConsoleColor.Black;
case ConsoleColor.DarkCyan: return ConsoleColor.Black;
case ConsoleColor.DarkGray: return ConsoleColor.Black;
case ConsoleColor.DarkGreen: return ConsoleColor.Black;
case ConsoleColor.DarkMagenta: return ConsoleColor.Black;
case ConsoleColor.DarkRed: return ConsoleColor.Black;
case ConsoleColor.DarkYellow: return ConsoleColor.Black;
case ConsoleColor.Gray: return ConsoleColor.White;
case ConsoleColor.Green: return ConsoleColor.DarkGreen;
case ConsoleColor.Magenta: return ConsoleColor.DarkMagenta;
case ConsoleColor.Red: return ConsoleColor.DarkRed;
case ConsoleColor.White: return ConsoleColor.Gray;
case ConsoleColor.Yellow: return ConsoleColor.DarkYellow;
default:
return ConsoleColor.Black;
}
}
private int _normalCursorSize = 10;
private static Dictionary<ConsoleKeyInfo, KeyHandler> _viInsKeyMap;
private static Dictionary<ConsoleKeyInfo, KeyHandler> _viCmdKeyMap;
private static Dictionary<ConsoleKeyInfo, KeyHandler> _viChordDTable;
private static Dictionary<ConsoleKeyInfo, KeyHandler> _viChordCTable;
private static Dictionary<ConsoleKeyInfo, KeyHandler> _viChordYTable;
private static Dictionary<ConsoleKeyInfo, Dictionary<ConsoleKeyInfo, KeyHandler>> _viCmdChordTable;
private static Dictionary<ConsoleKeyInfo, Dictionary<ConsoleKeyInfo, KeyHandler>> _viInsChordTable;
/// <summary>
/// Sets up the key bindings for vi operations.
/// </summary>
private void SetDefaultViBindings()
{
_viInsKeyMap = new Dictionary<ConsoleKeyInfo, KeyHandler>(new ConsoleKeyInfoComparer())
{
{ Keys.Enter, MakeKeyHandler(AcceptLine, "AcceptLine" ) },
{ Keys.CtrlD, MakeKeyHandler(ViAcceptLineOrExit, "ViAcceptLineOrExit" ) },
{ Keys.ShiftEnter, MakeKeyHandler(AddLine, "AddLine") },
{ Keys.Escape, MakeKeyHandler(ViCommandMode, "ViCommandMode") },
{ Keys.LeftArrow, MakeKeyHandler(BackwardChar, "BackwardChar") },
{ Keys.RightArrow, MakeKeyHandler(ForwardChar, "ForwardChar") },
{ Keys.CtrlLeftArrow, MakeKeyHandler(BackwardWord, "BackwardWord") },
{ Keys.CtrlRightArrow, MakeKeyHandler(NextWord, "NextWord") },
{ Keys.UpArrow, MakeKeyHandler(PreviousHistory, "PreviousHistory") },
{ Keys.DownArrow, MakeKeyHandler(NextHistory, "NextHistory") },
{ Keys.Home, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") },
{ Keys.End, MakeKeyHandler(EndOfLine, "EndOfLine") },
{ Keys.Delete, MakeKeyHandler(DeleteChar, "DeleteChar") },
{ Keys.Backspace, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") },
{ Keys.CtrlSpace, MakeKeyHandler(PossibleCompletions, "PossibleCompletions") },
{ Keys.Tab, MakeKeyHandler(ViTabCompleteNext, "ViTabCompleteNext") },
{ Keys.ShiftTab, MakeKeyHandler(ViTabCompletePrevious, "ViTabCompletePrevious") },
{ Keys.CtrlV, MakeKeyHandler(Paste, "Paste") },
#if !UNIX
{ Keys.VolumeDown, MakeKeyHandler(Ignore, "Ignore") },
{ Keys.VolumeUp, MakeKeyHandler(Ignore, "Ignore") },
{ Keys.VolumeMute, MakeKeyHandler(Ignore, "Ignore") },
#endif
{ Keys.CtrlC, MakeKeyHandler(CancelLine, "CancelLine") },
{ Keys.CtrlL, MakeKeyHandler(ClearScreen, "ClearScreen") },
{ Keys.CtrlY, MakeKeyHandler(Redo, "Redo") },
{ Keys.CtrlZ, MakeKeyHandler(Undo, "Undo") },
{ Keys.CtrlBackspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") },
{ Keys.CtrlDelete, MakeKeyHandler(KillWord, "KillWord") },
{ Keys.CtrlEnd, MakeKeyHandler(ForwardDeleteLine, "ForwardDeleteLine") },
{ Keys.CtrlHome, MakeKeyHandler(BackwardDeleteLine, "BackwardDeleteLine") },
{ Keys.CtrlRBracket, MakeKeyHandler(GotoBrace, "GotoBrace") },
{ Keys.F3, MakeKeyHandler(CharacterSearch, "CharacterSearch") },
{ Keys.ShiftF3, MakeKeyHandler(CharacterSearchBackward,"CharacterSearchBackward") },
{ Keys.CtrlAltQuestion, MakeKeyHandler(ShowKeyBindings, "ShowKeyBindings") }
};
_viCmdKeyMap = new Dictionary<ConsoleKeyInfo, KeyHandler>(new ConsoleKeyInfoComparer())
{
{ Keys.Enter, MakeKeyHandler(ViAcceptLine, "ViAcceptLine") },
{ Keys.CtrlD, MakeKeyHandler(ViAcceptLineOrExit, "ViAcceptLineOrExit") },
{ Keys.ShiftEnter, MakeKeyHandler(AddLine, "AddLine") },
{ Keys.Escape, MakeKeyHandler(Ding, "Ignore") },
{ Keys.LeftArrow, MakeKeyHandler(BackwardChar, "BackwardChar") },
{ Keys.RightArrow, MakeKeyHandler(ForwardChar, "ForwardChar") },
{ Keys.Space, MakeKeyHandler(ForwardChar, "ForwardChar") },
{ Keys.CtrlLeftArrow, MakeKeyHandler(BackwardWord, "BackwardWord") },
{ Keys.CtrlRightArrow, MakeKeyHandler(NextWord, "NextWord") },
{ Keys.UpArrow, MakeKeyHandler(PreviousHistory, "PreviousHistory") },
{ Keys.DownArrow, MakeKeyHandler(NextHistory, "NextHistory") },
{ Keys.Home, MakeKeyHandler(BeginningOfLine, "BeginningOfLine") },
{ Keys.End, MakeKeyHandler(MoveToEndOfLine, "MoveToEndOfLine") },
{ Keys.Delete, MakeKeyHandler(DeleteChar, "DeleteChar") },
{ Keys.Backspace, MakeKeyHandler(BackwardChar, "BackwardChar") },
{ Keys.CtrlSpace, MakeKeyHandler(PossibleCompletions, "PossibleCompletions") },
{ Keys.Tab, MakeKeyHandler(TabCompleteNext, "TabCompleteNext") },
{ Keys.ShiftTab, MakeKeyHandler(TabCompletePrevious, "TabCompletePrevious") },
{ Keys.CtrlV, MakeKeyHandler(Paste, "Paste") },
#if !UNIX
{ Keys.VolumeDown, MakeKeyHandler(Ignore, "Ignore") },
{ Keys.VolumeUp, MakeKeyHandler(Ignore, "Ignore") },
{ Keys.VolumeMute, MakeKeyHandler(Ignore, "Ignore") },
#endif
{ Keys.CtrlC, MakeKeyHandler(CancelLine, "CancelLine") },
{ Keys.CtrlL, MakeKeyHandler(ClearScreen, "ClearScreen") },
{ Keys.CtrlT, MakeKeyHandler(SwapCharacters, "SwapCharacters") },
{ Keys.CtrlU, MakeKeyHandler(BackwardDeleteLine, "BackwardDeleteLine") },
{ Keys.CtrlW, MakeKeyHandler(BackwardDeleteWord, "BackwardDeleteWord") },
{ Keys.CtrlY, MakeKeyHandler(Redo, "Redo") },
{ Keys.CtrlZ, MakeKeyHandler(Undo, "Undo") },
{ Keys.CtrlBackspace, MakeKeyHandler(BackwardKillWord, "BackwardKillWord") },
{ Keys.CtrlDelete, MakeKeyHandler(KillWord, "KillWord") },
{ Keys.CtrlEnd, MakeKeyHandler(ForwardDeleteLine, "ForwardDeleteLine") },
{ Keys.CtrlHome, MakeKeyHandler(BackwardDeleteLine, "BackwardDeleteLine") },
{ Keys.CtrlRBracket, MakeKeyHandler(GotoBrace, "GotoBrace") },
{ Keys.F3, MakeKeyHandler(CharacterSearch, "CharacterSearch") },
{ Keys.ShiftF3, MakeKeyHandler(CharacterSearchBackward, "CharacterSearchBackward") },
{ Keys.A, MakeKeyHandler(ViInsertWithAppend, "ViInsertWithAppend") },
{ Keys.B, MakeKeyHandler(ViBackwardWord, "ViBackwardWord") },
{ Keys.C, MakeKeyHandler(ViChord, "ChordFirstKey") },
{ Keys.D, MakeKeyHandler(ViChord, "ChordFirstKey") },
{ Keys.E, MakeKeyHandler(NextWordEnd, "NextWordEnd") },
{ Keys.F, MakeKeyHandler(SearchChar, "SearchChar") },
{ Keys.G, MakeKeyHandler(Ding, "Ignore") },
{ Keys.H, MakeKeyHandler(BackwardChar, "BackwardChar") },
{ Keys.I, MakeKeyHandler(ViInsertMode, "ViInsertMode") },
{ Keys.J, MakeKeyHandler(NextHistory, "NextHistory") },
{ Keys.K, MakeKeyHandler(PreviousHistory, "PreviousHistory") },
{ Keys.L, MakeKeyHandler(ForwardChar, "ForwardChar") },
{ Keys.M, MakeKeyHandler(Ding, "Ignore") },
{ Keys.N, MakeKeyHandler(RepeatSearch, "RepeatSearch") },
{ Keys.O, MakeKeyHandler(ViAppendLine, "ViAppendLine") },
{ Keys.P, MakeKeyHandler(PasteAfter, "PasteAfter") },
{ Keys.Q, MakeKeyHandler(Ding, "Ignore") },
{ Keys.R, MakeKeyHandler(ReplaceCharInPlace, "ReplaceCharInPlace") },
{ Keys.S, MakeKeyHandler(ViInsertWithDelete, "ViInsertWithDelete") },
{ Keys.T, MakeKeyHandler(SearchCharWithBackoff,"SearchCharWithBackoff") },
{ Keys.U, MakeKeyHandler(Undo, "Undo") },
{ Keys.V, MakeKeyHandler(ViEditVisually, "ViEditVisually") },
{ Keys.W, MakeKeyHandler(ViNextWord, "ViNextWord") },
{ Keys.X, MakeKeyHandler(DeleteChar, "DeleteChar") },
{ Keys.Y, MakeKeyHandler(ViChord, "ChordFirstKey") },
{ Keys.Z, MakeKeyHandler(Ding, "Ignore") },
{ Keys.ucA, MakeKeyHandler(ViInsertAtEnd, "ViInsertAtEnd") },
{ Keys.ucB, MakeKeyHandler(ViBackwardGlob, "ViBackwardGlob") },
{ Keys.ucC, MakeKeyHandler(ViReplaceToEnd, "ViReplaceToEnd") },
{ Keys.ucD, MakeKeyHandler(DeleteToEnd, "DeleteToEnd") },
{ Keys.ucE, MakeKeyHandler(ViEndOfGlob, "ViEndOfGlob") },
{ Keys.ucF, MakeKeyHandler(SearchCharBackward, "SearchCharBackward") },
{ Keys.ucG, MakeKeyHandler(Ding, "Ignore") },
{ Keys.ucH, MakeKeyHandler(Ding, "Ignore") },
{ Keys.ucI, MakeKeyHandler(ViInsertAtBegining, "ViInsertAtBegining") },
{ Keys.ucJ, MakeKeyHandler(ViJoinLines, "ViJoinLines") },
{ Keys.ucK, MakeKeyHandler(Ding, "Ignore") },
{ Keys.ucL, MakeKeyHandler(Ding, "Ignore") },
{ Keys.ucM, MakeKeyHandler(Ding, "Ignore") },
{ Keys.ucN, MakeKeyHandler(RepeatSearchBackward, "RepeatSearchBackward") },
{ Keys.ucO, MakeKeyHandler(ViInsertLine, "ViInsertLine") },
{ Keys.ucP, MakeKeyHandler(PasteBefore, "PasteBefore") },
{ Keys.ucQ, MakeKeyHandler(Ding, "Ignore") },
{ Keys.ucR, MakeKeyHandler(ViReplaceUntilEsc, "ViReplaceUntilEsc") },
{ Keys.ucS, MakeKeyHandler(ViReplaceLine, "ViReplaceLine") },
{ Keys.ucT, MakeKeyHandler(SearchCharBackwardWithBackoff, "SearchCharBackwardWithBackoff") },
{ Keys.ucU, MakeKeyHandler(UndoAll, "UndoAll") },
{ Keys.ucV, MakeKeyHandler(Ding, "Ignore") },
{ Keys.ucW, MakeKeyHandler(ViNextGlob, "ViNextGlob") },
{ Keys.ucX, MakeKeyHandler(BackwardDeleteChar, "BackwardDeleteChar") },
{ Keys.ucY, MakeKeyHandler(Ding, "Ignore") },
{ Keys.ucZ, MakeKeyHandler(Ding, "Ignore") },
{ Keys._0, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys._1, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys._2, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys._3, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys._4, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys._5, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys._6, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys._7, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys._8, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys._9, MakeKeyHandler(DigitArgument, "DigitArgument") },
{ Keys.Dollar, MakeKeyHandler(MoveToEndOfLine, "MoveToEndOfLine") },
{ Keys.Percent, MakeKeyHandler(ViGotoBrace, "ViGotoBrace") },
{ Keys.Pound, MakeKeyHandler(PrependAndAccept, "PrependAndAccept") },
{ Keys.Pipe, MakeKeyHandler(GotoColumn, "GotoColumn") },
{ Keys.Uphat, MakeKeyHandler(GotoFirstNonBlankOfLine, "GotoFirstNonBlankOfLine") },
{ Keys.Tilde, MakeKeyHandler(InvertCase, "InvertCase") },
{ Keys.Slash, MakeKeyHandler(ViSearchHistoryBackward, "SearchBackward") },
{ Keys.CtrlR, MakeKeyHandler(SearchCharBackward, "SearchCharBackward") },
{ Keys.Question, MakeKeyHandler(SearchForward, "SearchForward") },
{ Keys.CtrlS, MakeKeyHandler(SearchForward, "SearchForward") },
{ Keys.Plus, MakeKeyHandler(NextHistory, "NextHistory") },
{ Keys.Minus, MakeKeyHandler(PreviousHistory, "PreviousHistory") },
{ Keys.Period, MakeKeyHandler(RepeatLastCommand, "RepeatLastCommand") },
{ Keys.Semicolon, MakeKeyHandler(RepeatLastCharSearch, "RepeatLastCharSearch") },
{ Keys.Comma, MakeKeyHandler(RepeatLastCharSearchBackwards, "RepeatLastCharSearchBackwards") }
};
_viChordDTable = new Dictionary<ConsoleKeyInfo, KeyHandler>(new ConsoleKeyInfoComparer())
{
{ Keys.D, MakeKeyHandler( DeleteLine, "DeleteLine") },
{ Keys.Dollar, MakeKeyHandler( DeleteToEnd, "DeleteToEnd") },
{ Keys.B, MakeKeyHandler( BackwardDeleteWord, "BackwardDeleteWord") },
{ Keys.ucB, MakeKeyHandler( ViBackwardDeleteGlob, "ViBackwardDeleteGlob") },
{ Keys.W, MakeKeyHandler( DeleteWord, "DeleteWord") },
{ Keys.ucW, MakeKeyHandler( ViDeleteGlob, "ViDeleteGlob") },
{ Keys.E, MakeKeyHandler( DeleteEndOfWord, "DeleteEndOfWord") },
{ Keys.ucE, MakeKeyHandler( ViDeleteEndOfGlob, "ViDeleteEndOfGlob") },
{ Keys.H, MakeKeyHandler( BackwardDeleteChar, "BackwardDeleteChar") },
{ Keys.L, MakeKeyHandler( DeleteChar, "DeleteChar") },
{ Keys.Space, MakeKeyHandler( DeleteChar, "DeleteChar") },
{ Keys._0, MakeKeyHandler( BackwardDeleteLine, "BackwardDeleteLine") },
{ Keys.Uphat, MakeKeyHandler( DeleteLineToFirstChar, "DeleteLineToFirstChar") },
{ Keys.Percent, MakeKeyHandler( ViDeleteBrace, "DeleteBrace") },
{ Keys.F, MakeKeyHandler( ViDeleteToChar, "ViDeleteToChar") },
{ Keys.ucF, MakeKeyHandler( ViDeleteToCharBackward, "ViDeleteToCharBackward") },
{ Keys.T, MakeKeyHandler( ViDeleteToBeforeChar, "ViDeleteToBeforeChar") },
{ Keys.ucT, MakeKeyHandler( ViDeleteToBeforeCharBackward, "ViDeleteToBeforeCharBackward") },
};
_viChordCTable = new Dictionary<ConsoleKeyInfo, KeyHandler>(new ConsoleKeyInfoComparer())
{
{ Keys.C, MakeKeyHandler( ViReplaceLine, "ViReplaceLine") },
{ Keys.Dollar, MakeKeyHandler( ViReplaceToEnd, "ViReplaceToEnd") },
{ Keys.B, MakeKeyHandler( ViBackwardReplaceWord, "ViBackwardReplaceWord") },
{ Keys.ucB, MakeKeyHandler( ViBackwardReplaceGlob, "ViBackwardReplaceGlob") },
{ Keys.W, MakeKeyHandler( ViReplaceWord, "ViReplaceWord") },
{ Keys.ucW, MakeKeyHandler( ViReplaceGlob, "ViReplaceGlob") },
{ Keys.E, MakeKeyHandler( ViReplaceEndOfWord, "ViReplaceEndOfWord") },
{ Keys.ucE, MakeKeyHandler( ViReplaceEndOfGlob, "ViReplaceEndOfGlob") },
{ Keys.H, MakeKeyHandler( BackwardReplaceChar, "BackwardReplaceChar") },
{ Keys.L, MakeKeyHandler( ReplaceChar, "ReplaceChar") },
{ Keys.Space, MakeKeyHandler( ReplaceChar, "ReplaceChar") },
{ Keys._0, MakeKeyHandler( ViBackwardReplaceLine, "ViBackwardReplaceLine") },
{ Keys.Uphat, MakeKeyHandler( ViBackwardReplaceLineToFirstChar, "ViBackwardReplaceLineToFirstChar") },
{ Keys.Percent, MakeKeyHandler( ViReplaceBrace, "ViReplaceBrace") },
{ Keys.F, MakeKeyHandler( ViReplaceToChar, "ViReplaceToChar") },
{ Keys.ucF, MakeKeyHandler( ViReplaceToCharBackward, "ViReplaceToCharBackward") },
{ Keys.T, MakeKeyHandler( ViReplaceToBeforeChar, "ViReplaceToBeforeChar") },
{ Keys.ucT, MakeKeyHandler( ViReplaceToBeforeCharBackward, "ViReplaceToBeforeCharBackward") },
};
_viChordYTable = new Dictionary<ConsoleKeyInfo, KeyHandler>(new ConsoleKeyInfoComparer())
{
{ Keys.Y, MakeKeyHandler( ViYankLine, "ViYankLine") },
{ Keys.Dollar, MakeKeyHandler( ViYankToEndOfLine, "ViYankToEndOfLine") },
{ Keys.B, MakeKeyHandler( ViYankPreviousWord, "ViYankPreviousWord") },
{ Keys.ucB, MakeKeyHandler( ViYankPreviousGlob, "ViYankPreviousGlob") },
{ Keys.W, MakeKeyHandler( ViYankNextWord, "ViYankNextWord") },
{ Keys.ucW, MakeKeyHandler( ViYankNextGlob, "ViYankNextGlob") },
{ Keys.E, MakeKeyHandler( ViYankEndOfWord, "ViYankEndOfWord") },
{ Keys.ucE, MakeKeyHandler( ViYankEndOfGlob, "ViYankEndOfGlob") },
{ Keys.H, MakeKeyHandler( ViYankLeft, "ViYankLeft") },
{ Keys.L, MakeKeyHandler( ViYankRight, "ViYankRight") },
{ Keys.Space, MakeKeyHandler( ViYankRight, "ViYankRight") },
{ Keys._0, MakeKeyHandler( ViYankBeginningOfLine, "ViYankBeginningOfLine") },
{ Keys.Uphat, MakeKeyHandler( ViYankToFirstChar, "ViYankToFirstChar") },
{ Keys.Percent, MakeKeyHandler( ViYankPercent, "ViYankPercent") },
};
_viCmdChordTable = new Dictionary<ConsoleKeyInfo, Dictionary<ConsoleKeyInfo, KeyHandler>>();
_viInsChordTable = new Dictionary<ConsoleKeyInfo, Dictionary<ConsoleKeyInfo, KeyHandler>>();
_dispatchTable = _viInsKeyMap;
_chordDispatchTable = _viInsChordTable;
_viCmdChordTable[Keys.D] = _viChordDTable;
_viCmdChordTable[Keys.C] = _viChordCTable;
_viCmdChordTable[Keys.Y] = _viChordYTable;
_normalCursorSize = _console.CursorSize;
}
}
}

View file

@ -1,299 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
namespace Microsoft.PowerShell
{
internal static class Keys
{
public static ConsoleKeyInfo A = new ConsoleKeyInfo('a', ConsoleKey.A, false, false, false);
public static ConsoleKeyInfo B = new ConsoleKeyInfo('b', ConsoleKey.B, false, false, false);
public static ConsoleKeyInfo C = new ConsoleKeyInfo('c', ConsoleKey.C, false, false, false);
public static ConsoleKeyInfo D = new ConsoleKeyInfo('d', ConsoleKey.D, false, false, false);
public static ConsoleKeyInfo E = new ConsoleKeyInfo('e', ConsoleKey.E, false, false, false);
public static ConsoleKeyInfo F = new ConsoleKeyInfo('f', ConsoleKey.F, false, false, false);
public static ConsoleKeyInfo G = new ConsoleKeyInfo('g', ConsoleKey.G, false, false, false);
public static ConsoleKeyInfo H = new ConsoleKeyInfo('h', ConsoleKey.H, false, false, false);
public static ConsoleKeyInfo I = new ConsoleKeyInfo('i', ConsoleKey.I, false, false, false);
public static ConsoleKeyInfo J = new ConsoleKeyInfo('j', ConsoleKey.J, false, false, false);
public static ConsoleKeyInfo K = new ConsoleKeyInfo('k', ConsoleKey.K, false, false, false);
public static ConsoleKeyInfo L = new ConsoleKeyInfo('l', ConsoleKey.L, false, false, false);
public static ConsoleKeyInfo M = new ConsoleKeyInfo('m', ConsoleKey.M, false, false, false);
public static ConsoleKeyInfo N = new ConsoleKeyInfo('n', ConsoleKey.N, false, false, false);
public static ConsoleKeyInfo O = new ConsoleKeyInfo('o', ConsoleKey.O, false, false, false);
public static ConsoleKeyInfo P = new ConsoleKeyInfo('p', ConsoleKey.P, false, false, false);
public static ConsoleKeyInfo Q = new ConsoleKeyInfo('q', ConsoleKey.Q, false, false, false);
public static ConsoleKeyInfo R = new ConsoleKeyInfo('r', ConsoleKey.R, false, false, false);
public static ConsoleKeyInfo S = new ConsoleKeyInfo('s', ConsoleKey.S, false, false, false);
public static ConsoleKeyInfo T = new ConsoleKeyInfo('t', ConsoleKey.T, false, false, false);
public static ConsoleKeyInfo U = new ConsoleKeyInfo('u', ConsoleKey.U, false, false, false);
public static ConsoleKeyInfo V = new ConsoleKeyInfo('v', ConsoleKey.V, false, false, false);
public static ConsoleKeyInfo W = new ConsoleKeyInfo('w', ConsoleKey.W, false, false, false);
public static ConsoleKeyInfo X = new ConsoleKeyInfo('x', ConsoleKey.X, false, false, false);
public static ConsoleKeyInfo Y = new ConsoleKeyInfo('y', ConsoleKey.Y, false, false, false);
public static ConsoleKeyInfo Z = new ConsoleKeyInfo('z', ConsoleKey.Z, false, false, false);
public static ConsoleKeyInfo ucA = new ConsoleKeyInfo('A', ConsoleKey.A, true, false, false);
public static ConsoleKeyInfo ucB = new ConsoleKeyInfo('B', ConsoleKey.B, true, false, false);
public static ConsoleKeyInfo ucC = new ConsoleKeyInfo('C', ConsoleKey.C, true, false, false);
public static ConsoleKeyInfo ucD = new ConsoleKeyInfo('D', ConsoleKey.D, true, false, false);
public static ConsoleKeyInfo ucE = new ConsoleKeyInfo('E', ConsoleKey.E, true, false, false);
public static ConsoleKeyInfo ucF = new ConsoleKeyInfo('F', ConsoleKey.F, true, false, false);
public static ConsoleKeyInfo ucG = new ConsoleKeyInfo('G', ConsoleKey.G, true, false, false);
public static ConsoleKeyInfo ucH = new ConsoleKeyInfo('H', ConsoleKey.H, true, false, false);
public static ConsoleKeyInfo ucI = new ConsoleKeyInfo('I', ConsoleKey.I, true, false, false);
public static ConsoleKeyInfo ucJ = new ConsoleKeyInfo('J', ConsoleKey.J, true, false, false);
public static ConsoleKeyInfo ucK = new ConsoleKeyInfo('K', ConsoleKey.K, true, false, false);
public static ConsoleKeyInfo ucL = new ConsoleKeyInfo('L', ConsoleKey.L, true, false, false);
public static ConsoleKeyInfo ucM = new ConsoleKeyInfo('M', ConsoleKey.M, true, false, false);
public static ConsoleKeyInfo ucN = new ConsoleKeyInfo('N', ConsoleKey.N, true, false, false);
public static ConsoleKeyInfo ucO = new ConsoleKeyInfo('O', ConsoleKey.O, true, false, false);
public static ConsoleKeyInfo ucP = new ConsoleKeyInfo('P', ConsoleKey.P, true, false, false);
public static ConsoleKeyInfo ucQ = new ConsoleKeyInfo('Q', ConsoleKey.Q, true, false, false);
public static ConsoleKeyInfo ucR = new ConsoleKeyInfo('R', ConsoleKey.R, true, false, false);
public static ConsoleKeyInfo ucS = new ConsoleKeyInfo('S', ConsoleKey.S, true, false, false);
public static ConsoleKeyInfo ucT = new ConsoleKeyInfo('T', ConsoleKey.T, true, false, false);
public static ConsoleKeyInfo ucU = new ConsoleKeyInfo('U', ConsoleKey.U, true, false, false);
public static ConsoleKeyInfo ucV = new ConsoleKeyInfo('V', ConsoleKey.V, true, false, false);
public static ConsoleKeyInfo ucW = new ConsoleKeyInfo('W', ConsoleKey.W, true, false, false);
public static ConsoleKeyInfo ucX = new ConsoleKeyInfo('X', ConsoleKey.X, true, false, false);
public static ConsoleKeyInfo ucY = new ConsoleKeyInfo('Y', ConsoleKey.Y, true, false, false);
public static ConsoleKeyInfo ucZ = new ConsoleKeyInfo('Z', ConsoleKey.Z, true, false, false);
public static ConsoleKeyInfo _0 = new ConsoleKeyInfo('0', ConsoleKey.D0, false, false, false);
public static ConsoleKeyInfo _1 = new ConsoleKeyInfo('1', ConsoleKey.D1, false, false, false);
public static ConsoleKeyInfo _2 = new ConsoleKeyInfo('2', ConsoleKey.D2, false, false, false);
public static ConsoleKeyInfo _3 = new ConsoleKeyInfo('3', ConsoleKey.D3, false, false, false);
public static ConsoleKeyInfo _4 = new ConsoleKeyInfo('4', ConsoleKey.D4, false, false, false);
public static ConsoleKeyInfo _5 = new ConsoleKeyInfo('5', ConsoleKey.D5, false, false, false);
public static ConsoleKeyInfo _6 = new ConsoleKeyInfo('6', ConsoleKey.D6, false, false, false);
public static ConsoleKeyInfo _7 = new ConsoleKeyInfo('7', ConsoleKey.D7, false, false, false);
public static ConsoleKeyInfo _8 = new ConsoleKeyInfo('8', ConsoleKey.D8, false, false, false);
public static ConsoleKeyInfo _9 = new ConsoleKeyInfo('9', ConsoleKey.D9, false, false, false);
public static ConsoleKeyInfo RParen = new ConsoleKeyInfo(')', ConsoleKey.D0, true, false, false);
public static ConsoleKeyInfo Bang = new ConsoleKeyInfo('!', ConsoleKey.D1, true, false, false);
public static ConsoleKeyInfo At = new ConsoleKeyInfo('@', ConsoleKey.D2, true, false, false);
public static ConsoleKeyInfo Pound = new ConsoleKeyInfo('#', ConsoleKey.D3, true, false, false);
public static ConsoleKeyInfo Dollar = new ConsoleKeyInfo('$', ConsoleKey.D4, true, false, false);
public static ConsoleKeyInfo Percent = new ConsoleKeyInfo('%', ConsoleKey.D5, true, false, false);
public static ConsoleKeyInfo Uphat = new ConsoleKeyInfo('^', ConsoleKey.D6, true, false, false);
public static ConsoleKeyInfo Ampersand = new ConsoleKeyInfo('&', ConsoleKey.D7, true, false, false);
public static ConsoleKeyInfo Star = new ConsoleKeyInfo('*', ConsoleKey.D8, true, false, false);
public static ConsoleKeyInfo LParen = new ConsoleKeyInfo('(', ConsoleKey.D9, true, false, false);
public static ConsoleKeyInfo Colon = new ConsoleKeyInfo(':', ConsoleKey.Oem1, true, false, false);
public static ConsoleKeyInfo Semicolon = new ConsoleKeyInfo(';', ConsoleKey.Oem1, false, false, false);
public static ConsoleKeyInfo Question = new ConsoleKeyInfo('?', ConsoleKey.Oem2, true, false, false);
public static ConsoleKeyInfo Slash = new ConsoleKeyInfo('/', ConsoleKey.Oem2, false, false, false);
public static ConsoleKeyInfo Tilde = new ConsoleKeyInfo('~', ConsoleKey.Oem3, true, false, false);
public static ConsoleKeyInfo Backtick = new ConsoleKeyInfo('`', ConsoleKey.Oem3, false, false, false);
public static ConsoleKeyInfo LCurly = new ConsoleKeyInfo('{', ConsoleKey.Oem4, true, false, false);
public static ConsoleKeyInfo LBracket = new ConsoleKeyInfo('[', ConsoleKey.Oem4, false, false, false);
public static ConsoleKeyInfo Pipe = new ConsoleKeyInfo('|', ConsoleKey.Oem5, true, false, false);
public static ConsoleKeyInfo Backslash = new ConsoleKeyInfo('\\', ConsoleKey.Oem5, false, false, false);
public static ConsoleKeyInfo RCurly = new ConsoleKeyInfo('}', ConsoleKey.Oem6, true, false, false);
public static ConsoleKeyInfo RBracket = new ConsoleKeyInfo(']', ConsoleKey.Oem6, false, false, false);
public static ConsoleKeyInfo SQuote = new ConsoleKeyInfo('\'', ConsoleKey.Oem7, false, false, false);
public static ConsoleKeyInfo DQuote = new ConsoleKeyInfo('"', ConsoleKey.Oem7, true, false, false);
public static ConsoleKeyInfo LessThan = new ConsoleKeyInfo('<', ConsoleKey.OemComma, true, false, false);
public static ConsoleKeyInfo Comma = new ConsoleKeyInfo(',', ConsoleKey.OemComma, false, false, false);
public static ConsoleKeyInfo GreaterThan = new ConsoleKeyInfo('>', ConsoleKey.OemPeriod, true, false, false);
public static ConsoleKeyInfo Period = new ConsoleKeyInfo('.', ConsoleKey.OemPeriod, false, false, false);
public static ConsoleKeyInfo Underbar = new ConsoleKeyInfo('_', ConsoleKey.OemMinus, true, false, false);
public static ConsoleKeyInfo Minus = new ConsoleKeyInfo('-', ConsoleKey.OemMinus, false, false, false);
public static ConsoleKeyInfo AltMinus = new ConsoleKeyInfo('-', ConsoleKey.OemMinus, false, true, false);
public static ConsoleKeyInfo Plus = new ConsoleKeyInfo('+', ConsoleKey.OemPlus, true, false, false);
new
public static ConsoleKeyInfo Equals = new ConsoleKeyInfo('=', ConsoleKey.OemPlus, false, false, false);
public static ConsoleKeyInfo CtrlAt = new ConsoleKeyInfo((char)0, ConsoleKey.D2, true, false, true);
public static ConsoleKeyInfo AltUnderbar = new ConsoleKeyInfo('_', ConsoleKey.OemMinus, true, true, false);
public static ConsoleKeyInfo CtrlUnderbar = new ConsoleKeyInfo((char)31, ConsoleKey.OemMinus, true, false, true);
public static ConsoleKeyInfo AltEquals = new ConsoleKeyInfo('=', ConsoleKey.OemPlus, false, true, false);
public static ConsoleKeyInfo Space = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false);
// Useless because it's caught by the console to bring up the system menu.
public static ConsoleKeyInfo AltSpace = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, true, false);
public static ConsoleKeyInfo CtrlSpace = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, true);
public static ConsoleKeyInfo AltLess = new ConsoleKeyInfo('<', ConsoleKey.OemComma, true, true, false);
public static ConsoleKeyInfo AltGreater = new ConsoleKeyInfo('>', ConsoleKey.OemPeriod, true, true, false);
public static ConsoleKeyInfo CtrlRBracket = new ConsoleKeyInfo((char)29, ConsoleKey.Oem6, false, false, true);
public static ConsoleKeyInfo AltCtrlRBracket = new ConsoleKeyInfo((char)0, ConsoleKey.Oem6, false, true, true);
public static ConsoleKeyInfo AltPeriod = new ConsoleKeyInfo('.', ConsoleKey.OemPeriod, false, true, false);
public static ConsoleKeyInfo CtrlAltQuestion = new ConsoleKeyInfo((char)0, ConsoleKey.Oem2, true, true, true);
public static ConsoleKeyInfo AltQuestion = new ConsoleKeyInfo('?', ConsoleKey.Oem2, true, true, false);
public static ConsoleKeyInfo Alt0 = new ConsoleKeyInfo('0', ConsoleKey.D0, false, true, false);
public static ConsoleKeyInfo Alt1 = new ConsoleKeyInfo('1', ConsoleKey.D1, false, true, false);
public static ConsoleKeyInfo Alt2 = new ConsoleKeyInfo('2', ConsoleKey.D2, false, true, false);
public static ConsoleKeyInfo Alt3 = new ConsoleKeyInfo('3', ConsoleKey.D3, false, true, false);
public static ConsoleKeyInfo Alt4 = new ConsoleKeyInfo('4', ConsoleKey.D4, false, true, false);
public static ConsoleKeyInfo Alt5 = new ConsoleKeyInfo('5', ConsoleKey.D5, false, true, false);
public static ConsoleKeyInfo Alt6 = new ConsoleKeyInfo('6', ConsoleKey.D6, false, true, false);
public static ConsoleKeyInfo Alt7 = new ConsoleKeyInfo('7', ConsoleKey.D7, false, true, false);
public static ConsoleKeyInfo Alt8 = new ConsoleKeyInfo('8', ConsoleKey.D8, false, true, false);
public static ConsoleKeyInfo Alt9 = new ConsoleKeyInfo('9', ConsoleKey.D9, false, true, false);
public static ConsoleKeyInfo AltA = new ConsoleKeyInfo((char)97, ConsoleKey.A, false, true, false);
public static ConsoleKeyInfo AltB = new ConsoleKeyInfo((char)98, ConsoleKey.B, false, true, false);
public static ConsoleKeyInfo AltC = new ConsoleKeyInfo((char)99, ConsoleKey.C, false, true, false);
public static ConsoleKeyInfo AltD = new ConsoleKeyInfo((char)100, ConsoleKey.D, false, true, false);
public static ConsoleKeyInfo AltE = new ConsoleKeyInfo((char)101, ConsoleKey.E, false, true, false);
public static ConsoleKeyInfo AltF = new ConsoleKeyInfo((char)102, ConsoleKey.F, false, true, false);
public static ConsoleKeyInfo AltG = new ConsoleKeyInfo((char)103, ConsoleKey.G, false, true, false);
public static ConsoleKeyInfo AltH = new ConsoleKeyInfo((char)104, ConsoleKey.H, false, true, false);
public static ConsoleKeyInfo AltI = new ConsoleKeyInfo((char)105, ConsoleKey.I, false, true, false);
public static ConsoleKeyInfo AltJ = new ConsoleKeyInfo((char)106, ConsoleKey.J, false, true, false);
public static ConsoleKeyInfo AltK = new ConsoleKeyInfo((char)107, ConsoleKey.K, false, true, false);
public static ConsoleKeyInfo AltL = new ConsoleKeyInfo((char)108, ConsoleKey.L, false, true, false);
public static ConsoleKeyInfo AltM = new ConsoleKeyInfo((char)109, ConsoleKey.M, false, true, false);
public static ConsoleKeyInfo AltN = new ConsoleKeyInfo((char)110, ConsoleKey.N, false, true, false);
public static ConsoleKeyInfo AltO = new ConsoleKeyInfo((char)111, ConsoleKey.O, false, true, false);
public static ConsoleKeyInfo AltP = new ConsoleKeyInfo((char)112, ConsoleKey.P, false, true, false);
public static ConsoleKeyInfo AltQ = new ConsoleKeyInfo((char)113, ConsoleKey.Q, false, true, false);
public static ConsoleKeyInfo AltR = new ConsoleKeyInfo((char)114, ConsoleKey.R, false, true, false);
public static ConsoleKeyInfo AltS = new ConsoleKeyInfo((char)115, ConsoleKey.S, false, true, false);
public static ConsoleKeyInfo AltT = new ConsoleKeyInfo((char)116, ConsoleKey.T, false, true, false);
public static ConsoleKeyInfo AltU = new ConsoleKeyInfo((char)117, ConsoleKey.U, false, true, false);
public static ConsoleKeyInfo AltV = new ConsoleKeyInfo((char)118, ConsoleKey.V, false, true, false);
public static ConsoleKeyInfo AltW = new ConsoleKeyInfo((char)119, ConsoleKey.W, false, true, false);
public static ConsoleKeyInfo AltX = new ConsoleKeyInfo((char)120, ConsoleKey.X, false, true, false);
public static ConsoleKeyInfo AltY = new ConsoleKeyInfo((char)121, ConsoleKey.Y, false, true, false);
public static ConsoleKeyInfo AltZ = new ConsoleKeyInfo((char)122, ConsoleKey.Z, false, true, false);
public static ConsoleKeyInfo CtrlA = new ConsoleKeyInfo((char)1, ConsoleKey.A, false, false, true);
public static ConsoleKeyInfo CtrlB = new ConsoleKeyInfo((char)2, ConsoleKey.B, false, false, true);
public static ConsoleKeyInfo CtrlC = new ConsoleKeyInfo((char)3, ConsoleKey.C, false, false, true);
public static ConsoleKeyInfo CtrlD = new ConsoleKeyInfo((char)4, ConsoleKey.D, false, false, true);
public static ConsoleKeyInfo CtrlE = new ConsoleKeyInfo((char)5, ConsoleKey.E, false, false, true);
public static ConsoleKeyInfo CtrlF = new ConsoleKeyInfo((char)6, ConsoleKey.F, false, false, true);
public static ConsoleKeyInfo CtrlG = new ConsoleKeyInfo((char)7, ConsoleKey.G, false, false, true);
public static ConsoleKeyInfo CtrlH = new ConsoleKeyInfo((char)8, ConsoleKey.H, false, false, true);
public static ConsoleKeyInfo CtrlI = new ConsoleKeyInfo((char)9, ConsoleKey.I, false, false, true);
public static ConsoleKeyInfo CtrlJ = new ConsoleKeyInfo((char)10, ConsoleKey.J, false, false, true);
public static ConsoleKeyInfo CtrlK = new ConsoleKeyInfo((char)11, ConsoleKey.K, false, false, true);
public static ConsoleKeyInfo CtrlL = new ConsoleKeyInfo((char)12, ConsoleKey.L, false, false, true);
public static ConsoleKeyInfo CtrlM = new ConsoleKeyInfo((char)13, ConsoleKey.M, false, false, true);
public static ConsoleKeyInfo CtrlN = new ConsoleKeyInfo((char)14, ConsoleKey.N, false, false, true);
public static ConsoleKeyInfo CtrlO = new ConsoleKeyInfo((char)15, ConsoleKey.O, false, false, true);
public static ConsoleKeyInfo CtrlP = new ConsoleKeyInfo((char)16, ConsoleKey.P, false, false, true);
public static ConsoleKeyInfo CtrlQ = new ConsoleKeyInfo((char)17, ConsoleKey.Q, false, false, true);
public static ConsoleKeyInfo CtrlR = new ConsoleKeyInfo((char)18, ConsoleKey.R, false, false, true);
public static ConsoleKeyInfo CtrlS = new ConsoleKeyInfo((char)19, ConsoleKey.S, false, false, true);
public static ConsoleKeyInfo CtrlT = new ConsoleKeyInfo((char)20, ConsoleKey.T, false, false, true);
public static ConsoleKeyInfo CtrlU = new ConsoleKeyInfo((char)21, ConsoleKey.U, false, false, true);
public static ConsoleKeyInfo CtrlV = new ConsoleKeyInfo((char)22, ConsoleKey.V, false, false, true);
public static ConsoleKeyInfo CtrlW = new ConsoleKeyInfo((char)23, ConsoleKey.W, false, false, true);
public static ConsoleKeyInfo CtrlX = new ConsoleKeyInfo((char)24, ConsoleKey.X, false, false, true);
public static ConsoleKeyInfo CtrlY = new ConsoleKeyInfo((char)25, ConsoleKey.Y, false, false, true);
public static ConsoleKeyInfo CtrlZ = new ConsoleKeyInfo((char)26, ConsoleKey.Z, false, false, true);
public static ConsoleKeyInfo CtrlShiftC = new ConsoleKeyInfo((char)3, ConsoleKey.C, true, false, true);
public static ConsoleKeyInfo AltShiftB = new ConsoleKeyInfo('B', ConsoleKey.B, true, true, false);
public static ConsoleKeyInfo AltShiftF = new ConsoleKeyInfo('F', ConsoleKey.F, true, true, false);
public static ConsoleKeyInfo AltCtrlY = new ConsoleKeyInfo((char)0, ConsoleKey.Y, false, true, true);
public static ConsoleKeyInfo Backspace = new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, false, false);
public static ConsoleKeyInfo CtrlBackspace = new ConsoleKeyInfo((char)0x7f, ConsoleKey.Backspace, false, false, true);
public static ConsoleKeyInfo AltBackspace = new ConsoleKeyInfo((char)8, ConsoleKey.Backspace, false, true, false);
public static ConsoleKeyInfo Delete = new ConsoleKeyInfo((char)0, ConsoleKey.Delete, false, false, false);
public static ConsoleKeyInfo CtrlDelete = new ConsoleKeyInfo((char)0, ConsoleKey.Delete, false, false, true);
public static ConsoleKeyInfo DownArrow = new ConsoleKeyInfo((char)0, ConsoleKey.DownArrow, false, false, false);
public static ConsoleKeyInfo End = new ConsoleKeyInfo((char)0, ConsoleKey.End, false, false, false);
public static ConsoleKeyInfo CtrlEnd = new ConsoleKeyInfo((char)0, ConsoleKey.End, false, false, true);
public static ConsoleKeyInfo ShiftEnd = new ConsoleKeyInfo((char)0, ConsoleKey.End, true, false, false);
public static ConsoleKeyInfo Enter = new ConsoleKeyInfo((char)13, ConsoleKey.Enter, false, false, false);
public static ConsoleKeyInfo Escape = new ConsoleKeyInfo((char)27, ConsoleKey.Escape, false, false, false);
public static ConsoleKeyInfo Home = new ConsoleKeyInfo((char)0, ConsoleKey.Home, false, false, false);
public static ConsoleKeyInfo CtrlHome = new ConsoleKeyInfo((char)0, ConsoleKey.Home, false, false, true);
public static ConsoleKeyInfo ShiftHome = new ConsoleKeyInfo((char)0, ConsoleKey.Home, true, false, false);
public static ConsoleKeyInfo LeftArrow = new ConsoleKeyInfo((char)0, ConsoleKey.LeftArrow, false, false, false);
public static ConsoleKeyInfo RightArrow = new ConsoleKeyInfo((char)0, ConsoleKey.RightArrow, false, false, false);
public static ConsoleKeyInfo Tab = new ConsoleKeyInfo((char)9, ConsoleKey.Tab, false, false, false);
public static ConsoleKeyInfo UpArrow = new ConsoleKeyInfo((char)0, ConsoleKey.UpArrow, false, false, false);
public static ConsoleKeyInfo PageUp = new ConsoleKeyInfo((char)0, ConsoleKey.PageUp, false, false, false);
public static ConsoleKeyInfo PageDown = new ConsoleKeyInfo((char)0, ConsoleKey.PageDown, false, false, false);
public static ConsoleKeyInfo ShiftPageUp = new ConsoleKeyInfo((char)0, ConsoleKey.PageUp, true, false, false);
public static ConsoleKeyInfo ShiftPageDown = new ConsoleKeyInfo((char)0, ConsoleKey.PageDown, true, false, false);
public static ConsoleKeyInfo CtrlPageUp = new ConsoleKeyInfo((char)0, ConsoleKey.PageUp, false, false, true);
public static ConsoleKeyInfo CtrlPageDown = new ConsoleKeyInfo((char)0, ConsoleKey.PageDown, false, false, true);
public static ConsoleKeyInfo AltPageUp = new ConsoleKeyInfo((char)0, ConsoleKey.PageUp, false, true, false);
public static ConsoleKeyInfo AltPageDown = new ConsoleKeyInfo((char)0, ConsoleKey.PageDown, false, true, false);
public static ConsoleKeyInfo ShiftLeftArrow = new ConsoleKeyInfo((char)0, ConsoleKey.LeftArrow, true, false, false);
public static ConsoleKeyInfo ShiftRightArrow = new ConsoleKeyInfo((char)0, ConsoleKey.RightArrow, true, false, false);
public static ConsoleKeyInfo CtrlLeftArrow = new ConsoleKeyInfo((char)0, ConsoleKey.LeftArrow, false, false, true);
public static ConsoleKeyInfo CtrlRightArrow = new ConsoleKeyInfo((char)0, ConsoleKey.RightArrow, false, false, true);
public static ConsoleKeyInfo ShiftCtrlLeftArrow = new ConsoleKeyInfo((char)0, ConsoleKey.LeftArrow, true, false, true);
public static ConsoleKeyInfo ShiftCtrlRightArrow = new ConsoleKeyInfo((char)0, ConsoleKey.RightArrow, true, false, true);
public static ConsoleKeyInfo ShiftTab = new ConsoleKeyInfo((char)9, ConsoleKey.Tab, true, false, false);
public static ConsoleKeyInfo CtrlEnter = new ConsoleKeyInfo((char)10, ConsoleKey.Enter, false, false, true);
public static ConsoleKeyInfo CtrlShiftEnter = new ConsoleKeyInfo((char)0, ConsoleKey.Enter, true, false, true);
public static ConsoleKeyInfo ShiftEnter = new ConsoleKeyInfo((char)13, ConsoleKey.Enter, true, false, false);
public static ConsoleKeyInfo F1 = new ConsoleKeyInfo((char)0, ConsoleKey.F1, false, false, false);
public static ConsoleKeyInfo F2 = new ConsoleKeyInfo((char)0, ConsoleKey.F2, false, false, false);
public static ConsoleKeyInfo F3 = new ConsoleKeyInfo((char)0, ConsoleKey.F3, false, false, false);
public static ConsoleKeyInfo F4 = new ConsoleKeyInfo((char)0, ConsoleKey.F4, false, false, false);
public static ConsoleKeyInfo F5 = new ConsoleKeyInfo((char)0, ConsoleKey.F5, false, false, false);
public static ConsoleKeyInfo F6 = new ConsoleKeyInfo((char)0, ConsoleKey.F6, false, false, false);
public static ConsoleKeyInfo F7 = new ConsoleKeyInfo((char)0, ConsoleKey.F7, false, false, false);
public static ConsoleKeyInfo F8 = new ConsoleKeyInfo((char)0, ConsoleKey.F8, false, false, false);
public static ConsoleKeyInfo F9 = new ConsoleKeyInfo((char)0, ConsoleKey.F9, false, false, false);
public static ConsoleKeyInfo Fl0 = new ConsoleKeyInfo((char)0, ConsoleKey.F10, false, false, false);
public static ConsoleKeyInfo F11 = new ConsoleKeyInfo((char)0, ConsoleKey.F11, false, false, false);
public static ConsoleKeyInfo F12 = new ConsoleKeyInfo((char)0, ConsoleKey.F12, false, false, false);
public static ConsoleKeyInfo F13 = new ConsoleKeyInfo((char)0, ConsoleKey.F13, false, false, false);
public static ConsoleKeyInfo F14 = new ConsoleKeyInfo((char)0, ConsoleKey.F14, false, false, false);
public static ConsoleKeyInfo F15 = new ConsoleKeyInfo((char)0, ConsoleKey.F15, false, false, false);
public static ConsoleKeyInfo F16 = new ConsoleKeyInfo((char)0, ConsoleKey.F16, false, false, false);
public static ConsoleKeyInfo F17 = new ConsoleKeyInfo((char)0, ConsoleKey.F17, false, false, false);
public static ConsoleKeyInfo F18 = new ConsoleKeyInfo((char)0, ConsoleKey.F18, false, false, false);
public static ConsoleKeyInfo F19 = new ConsoleKeyInfo((char)0, ConsoleKey.F19, false, false, false);
public static ConsoleKeyInfo F20 = new ConsoleKeyInfo((char)0, ConsoleKey.F20, false, false, false);
public static ConsoleKeyInfo F21 = new ConsoleKeyInfo((char)0, ConsoleKey.F21, false, false, false);
public static ConsoleKeyInfo F22 = new ConsoleKeyInfo((char)0, ConsoleKey.F22, false, false, false);
public static ConsoleKeyInfo F23 = new ConsoleKeyInfo((char)0, ConsoleKey.F23, false, false, false);
public static ConsoleKeyInfo F24 = new ConsoleKeyInfo((char)0, ConsoleKey.F24, false, false, false);
public static ConsoleKeyInfo AltF1 = new ConsoleKeyInfo((char)0, ConsoleKey.F1, false, true, false);
public static ConsoleKeyInfo AltF2 = new ConsoleKeyInfo((char)0, ConsoleKey.F2, false, true, false);
public static ConsoleKeyInfo AltF3 = new ConsoleKeyInfo((char)0, ConsoleKey.F3, false, true, false);
public static ConsoleKeyInfo AltF4 = new ConsoleKeyInfo((char)0, ConsoleKey.F4, false, true, false);
public static ConsoleKeyInfo AltF5 = new ConsoleKeyInfo((char)0, ConsoleKey.F5, false, true, false);
public static ConsoleKeyInfo AltF6 = new ConsoleKeyInfo((char)0, ConsoleKey.F6, false, true, false);
public static ConsoleKeyInfo AltF7 = new ConsoleKeyInfo((char)0, ConsoleKey.F7, false, true, false);
public static ConsoleKeyInfo AltF8 = new ConsoleKeyInfo((char)0, ConsoleKey.F8, false, true, false);
public static ConsoleKeyInfo AltF9 = new ConsoleKeyInfo((char)0, ConsoleKey.F9, false, true, false);
public static ConsoleKeyInfo AltFl0 = new ConsoleKeyInfo((char)0, ConsoleKey.F10, false, true, false);
public static ConsoleKeyInfo AltF11 = new ConsoleKeyInfo((char)0, ConsoleKey.F11, false, true, false);
public static ConsoleKeyInfo AltF12 = new ConsoleKeyInfo((char)0, ConsoleKey.F12, false, true, false);
public static ConsoleKeyInfo AltF13 = new ConsoleKeyInfo((char)0, ConsoleKey.F13, false, true, false);
public static ConsoleKeyInfo AltF14 = new ConsoleKeyInfo((char)0, ConsoleKey.F14, false, true, false);
public static ConsoleKeyInfo AltF15 = new ConsoleKeyInfo((char)0, ConsoleKey.F15, false, true, false);
public static ConsoleKeyInfo AltF16 = new ConsoleKeyInfo((char)0, ConsoleKey.F16, false, true, false);
public static ConsoleKeyInfo AltF17 = new ConsoleKeyInfo((char)0, ConsoleKey.F17, false, true, false);
public static ConsoleKeyInfo AltF18 = new ConsoleKeyInfo((char)0, ConsoleKey.F18, false, true, false);
public static ConsoleKeyInfo AltF19 = new ConsoleKeyInfo((char)0, ConsoleKey.F19, false, true, false);
public static ConsoleKeyInfo AltF20 = new ConsoleKeyInfo((char)0, ConsoleKey.F20, false, true, false);
public static ConsoleKeyInfo AltF21 = new ConsoleKeyInfo((char)0, ConsoleKey.F21, false, true, false);
public static ConsoleKeyInfo AltF22 = new ConsoleKeyInfo((char)0, ConsoleKey.F22, false, true, false);
public static ConsoleKeyInfo AltF23 = new ConsoleKeyInfo((char)0, ConsoleKey.F23, false, true, false);
public static ConsoleKeyInfo AltF24 = new ConsoleKeyInfo((char)0, ConsoleKey.F24, false, true, false);
public static ConsoleKeyInfo ShiftF3 = new ConsoleKeyInfo((char)0, ConsoleKey.F3, true, false, false);
public static ConsoleKeyInfo ShiftF8 = new ConsoleKeyInfo((char)0, ConsoleKey.F8, true, false, false);
// Keys to ignore
#if !UNIX
public static ConsoleKeyInfo VolumeUp = new ConsoleKeyInfo((char)0, /*ConsoleKey.VolumeUp*/(ConsoleKey)175, false, false, false);
public static ConsoleKeyInfo VolumeDown = new ConsoleKeyInfo((char)0, /*ConsoleKey.VolumeDown*/(ConsoleKey)174, false, false, false);
public static ConsoleKeyInfo VolumeMute = new ConsoleKeyInfo((char)0, /*ConsoleKey.VolumeMute*/(ConsoleKey)173, false, false, false);
#endif
}
}

View file

@ -1,565 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Management.Automation.Language;
#if !CORECLR // TODO: clipboard
using System.Windows.Forms;
#endif
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
// Yank/Kill state
private List<string> _killRing;
private int _killIndex;
private int _killCommandCount;
private int _yankCommandCount;
private int _yankStartPoint;
private int _yankLastArgCommandCount;
class YankLastArgState
{
internal int argument;
internal int historyIndex;
internal int historyIncrement;
internal int startPoint = -1;
}
private YankLastArgState _yankLastArgState;
private int _visualSelectionCommandCount;
/// <summary>
/// Mark the current location of the cursor for use in a subsequent editing command.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SetMark(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton._mark = _singleton._current;
}
/// <summary>
/// The cursor is placed at the location of the mark and the mark is moved
/// to the location of the cursor.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ExchangePointAndMark(ConsoleKeyInfo? key = null, object arg = null)
{
var tmp = _singleton._mark;
_singleton._mark = _singleton._current;
_singleton._current = tmp;
_singleton.PlaceCursor();
}
/// <summary>
/// The contents of the kill ring are cleared.
/// </summary>
public static void ClearKillRing()
{
if (_singleton._killRing != null)
{
_singleton._killRing.Clear();
}
_singleton._killIndex = -1; // So first add indexes 0.
}
private void Kill(int start, int length, bool prepend)
{
if (length > 0)
{
var killText = _buffer.ToString(start, length);
SaveEditItem(EditItemDelete.Create(killText, start));
_buffer.Remove(start, length);
_current = start;
Render();
if (_killCommandCount > 0)
{
if (prepend)
{
_killRing[_killIndex] = killText + _killRing[_killIndex];
}
else
{
_killRing[_killIndex] += killText;
}
}
else
{
if (_killRing.Count < Options.MaximumKillRingCount)
{
_killRing.Add(killText);
_killIndex = _killRing.Count - 1;
}
else
{
_killIndex += 1;
if (_killIndex == _killRing.Count)
{
_killIndex = 0;
}
_killRing[_killIndex] = killText;
}
}
}
_killCommandCount += 1;
}
/// <summary>
/// Clear the input from the cursor to the end of the input. The cleared text is placed
/// in the kill ring.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void KillLine(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.Kill(_singleton._current, _singleton._buffer.Length - _singleton._current, false);
}
/// <summary>
/// Clear the input from the start of the input to the cursor. The cleared text is placed
/// in the kill ring.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void BackwardKillLine(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.Kill(0, _singleton._current, true);
}
/// <summary>
/// Clear the input from the cursor to the end of the current word. If the cursor
/// is between words, the input is cleared from the cursor to the end of the next word.
/// The cleared text is placed in the kill ring.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void KillWord(ConsoleKeyInfo? key = null, object arg = null)
{
int i = _singleton.FindForwardWordPoint(_singleton.Options.WordDelimiters);
_singleton.Kill(_singleton._current, i - _singleton._current, false);
}
/// <summary>
/// Clear the input from the cursor to the end of the current word. If the cursor
/// is between words, the input is cleared from the cursor to the end of the next word.
/// The cleared text is placed in the kill ring.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ShellKillWord(ConsoleKeyInfo? key = null, object arg = null)
{
var token = _singleton.FindToken(_singleton._current, FindTokenMode.CurrentOrNext);
var end = (token.Kind == TokenKind.EndOfInput)
? _singleton._buffer.Length
: token.Extent.EndOffset;
_singleton.Kill(_singleton._current, end - _singleton._current, false);
}
/// <summary>
/// Clear the input from the start of the current word to the cursor. If the cursor
/// is between words, the input is cleared from the start of the previous word to the
/// cursor. The cleared text is placed in the kill ring.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void BackwardKillWord(ConsoleKeyInfo? key = null, object arg = null)
{
int i = _singleton.FindBackwardWordPoint(_singleton.Options.WordDelimiters);
_singleton.Kill(i, _singleton._current - i, true);
}
/// <summary>
/// Clear the input from the start of the current word to the cursor. If the cursor
/// is between words, the input is cleared from the start of the previous word to the
/// cursor. The cleared text is placed in the kill ring.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void UnixWordRubout(ConsoleKeyInfo? key = null, object arg = null)
{
int i = _singleton.FindBackwardWordPoint("");
_singleton.Kill(i, _singleton._current - i, true);
}
/// <summary>
/// Clear the input from the start of the current word to the cursor. If the cursor
/// is between words, the input is cleared from the start of the previous word to the
/// cursor. The cleared text is placed in the kill ring.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ShellBackwardKillWord(ConsoleKeyInfo? key = null, object arg = null)
{
var token = _singleton.FindToken(_singleton._current, FindTokenMode.Previous);
var start = token == null
? 0
: token.Extent.StartOffset;
_singleton.Kill(start, _singleton._current - start, true);
}
/// <summary>
/// Kill the text between the cursor and the mark.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void KillRegion(ConsoleKeyInfo? key = null, object arg = null)
{
int start, length;
_singleton.GetRegion(out start, out length);
_singleton.Kill(start, length, true);
}
private void YankImpl()
{
if (_killRing.Count == 0)
return;
// Starting a yank session, yank the last thing killed and
// remember where we started.
_mark = _yankStartPoint = _current;
Insert(_killRing[_killIndex]);
_yankCommandCount += 1;
}
/// <summary>
/// Add the most recently killed text to the input.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void Yank(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.YankImpl();
}
private void YankPopImpl()
{
if (_yankCommandCount == 0)
return;
_killIndex -= 1;
if (_killIndex < 0)
{
_killIndex = _killRing.Count - 1;
}
var yankText = _killRing[_killIndex];
Replace(_yankStartPoint, _current - _yankStartPoint, yankText);
_yankCommandCount += 1;
}
/// <summary>
/// If the previous operation was Yank or YankPop, replace the previously yanked
/// text with the next killed text from the kill ring.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void YankPop(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.YankPopImpl();
}
void YankArgImpl(YankLastArgState yankLastArgState)
{
if (yankLastArgState.historyIndex < 0 || yankLastArgState.historyIndex >= _history.Count)
{
Ding();
return;
}
Token[] tokens;
ParseError[] errors;
var buffer = _history[yankLastArgState.historyIndex];
Parser.ParseInput(buffer._line, out tokens, out errors);
int arg = (yankLastArgState.argument < 0)
? tokens.Length + yankLastArgState.argument - 1
: yankLastArgState.argument;
if (arg < 0 || arg >= tokens.Length)
{
Ding();
return;
}
var argText = tokens[arg].Text;
if (yankLastArgState.startPoint < 0)
{
yankLastArgState.startPoint = _current;
Insert(argText);
}
else
{
Replace(yankLastArgState.startPoint, _current - yankLastArgState.startPoint, argText);
}
}
/// <summary>
/// Yank the first argument (after the command) from the previous history line.
/// With an argument, yank the nth argument (starting from 0), if the argument
/// is negative, start from the last argument.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void YankNthArg(ConsoleKeyInfo? key = null, object arg = null)
{
var yankLastArgState = new YankLastArgState
{
argument = (arg is int) ? (int)arg : 1,
historyIndex = _singleton._currentHistoryIndex - 1,
};
_singleton.YankArgImpl(yankLastArgState);
}
/// <summary>
/// Yank the last argument from the previous history line. With an argument,
/// the first time it is invoked, behaves just like YankNthArg. If invoked
/// multiple times, instead it iterates through history and arg sets the direction
/// (negative reverses the direction.)
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void YankLastArg(ConsoleKeyInfo? key = null, object arg = null)
{
if (arg != null && !(arg is int))
{
Ding();
return;
}
_singleton._yankLastArgCommandCount += 1;
if (_singleton._yankLastArgCommandCount == 1)
{
_singleton._yankLastArgState = new YankLastArgState
{
argument = (arg != null) ? (int)arg : -1,
historyIncrement = -1,
historyIndex = _singleton._currentHistoryIndex - 1
};
_singleton.YankArgImpl(_singleton._yankLastArgState);
return;
}
var yankLastArgState = _singleton._yankLastArgState;
if (arg != null)
{
if ((int)arg < 0)
{
yankLastArgState.historyIncrement = -yankLastArgState.historyIncrement;
}
}
yankLastArgState.historyIndex += yankLastArgState.historyIncrement;
// Don't increment more than 1 out of range so it's quick to get back to being in range.
if (yankLastArgState.historyIndex < 0)
{
Ding();
yankLastArgState.historyIndex = 0;
}
else if (yankLastArgState.historyIndex >= _singleton._history.Count)
{
Ding();
yankLastArgState.historyIndex = _singleton._history.Count - 1;
}
else
{
_singleton.YankArgImpl(yankLastArgState);
}
}
private void VisualSelectionCommon(Action action)
{
if (_singleton._visualSelectionCommandCount == 0)
{
SetMark();
}
_singleton._visualSelectionCommandCount += 1;
action();
_singleton.Render();
}
/// <summary>
/// Adjust the current selection to include the previous character
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SelectBackwardChar(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.VisualSelectionCommon(() => BackwardChar(key, arg));
}
/// <summary>
/// Adjust the current selection to include the next character
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SelectForwardChar(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.VisualSelectionCommon(() => ForwardChar(key, arg));
}
/// <summary>
/// Adjust the current selection to include the previous word
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SelectBackwardWord(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.VisualSelectionCommon(() => BackwardWord(key, arg));
}
/// <summary>
/// Adjust the current selection to include the next word
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SelectNextWord(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.VisualSelectionCommon(() => NextWord(key, arg));
}
/// <summary>
/// Adjust the current selection to include the next word using ForwardWord
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SelectForwardWord(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.VisualSelectionCommon(() => ForwardWord(key, arg));
}
/// <summary>
/// Adjust the current selection to include the next word using ShellForwardWord
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SelectShellForwardWord(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.VisualSelectionCommon(() => ShellForwardWord(key, arg));
}
/// <summary>
/// Adjust the current selection to include the next word using ShellNextWord
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SelectShellNextWord(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.VisualSelectionCommon(() => ShellNextWord(key, arg));
}
/// <summary>
/// Adjust the current selection to include the previous word using ShellBackwardWord
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SelectShellBackwardWord(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.VisualSelectionCommon(() => ShellBackwardWord(key, arg));
}
/// <summary>
/// Select the entire line
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SelectAll(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton._visualSelectionCommandCount += 1;
_singleton._mark = 0;
_singleton._current = _singleton._buffer.Length;
_singleton.Render();
}
/// <summary>
/// Adjust the current selection to include from the cursor to the end of the line
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SelectLine(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.VisualSelectionCommon(() => EndOfLine(key, arg));
}
/// <summary>
/// Adjust the current selection to include from the cursor to the start of the line
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void SelectBackwardsLine(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.VisualSelectionCommon(() => BeginningOfLine(key, arg));
}
/// <summary>
/// Paste text from the system clipboard.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void Paste(ConsoleKeyInfo? key = null, object arg = null)
{
#if !CORECLR // TODO: clipboard
string textToPaste = null;
ExecuteOnSTAThread(() => {
if (Clipboard.ContainsText())
{
textToPaste = Clipboard.GetText();
}
});
if (textToPaste != null)
{
textToPaste = textToPaste.Replace("\r", "");
if (_singleton._visualSelectionCommandCount > 0)
{
int start, length;
_singleton.GetRegion(out start, out length);
Replace(start, length, textToPaste);
}
else
{
Insert(textToPaste);
}
}
#endif
}
/// <summary>
/// Copy selected region to the system clipboard. If no region is selected, copy the whole line.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void Copy(ConsoleKeyInfo? key = null, object arg = null)
{
#if !CORECLR // TODO: clipboard
string textToSet;
if (_singleton._visualSelectionCommandCount > 0)
{
int start, length;
_singleton.GetRegion(out start, out length);
textToSet = _singleton._buffer.ToString(start, length);
}
else
{
textToSet = _singleton._buffer.ToString();
}
if (!string.IsNullOrEmpty(textToSet))
{
ExecuteOnSTAThread(() => Clipboard.SetText(textToSet));
}
#endif
}
/// <summary>
/// If text is selected, copy to the clipboard, otherwise cancel the line.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void CopyOrCancelLine(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton._visualSelectionCommandCount > 0)
{
Copy(key, arg);
}
else
{
CancelLine(key, arg);
}
}
/// <summary>
/// Delete selected region placing deleted text in the system clipboard.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void Cut(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton._visualSelectionCommandCount > 0)
{
int start, length;
_singleton.GetRegion(out start, out length);
#if !CORECLR // TODO: clipboard
ExecuteOnSTAThread(() => Clipboard.SetText(_singleton._buffer.ToString(start, length)));
#endif
Delete(start, length);
}
}
}
}

View file

@ -1,22 +0,0 @@
Copyright (c) 2013, Jason Shirk
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,28 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<Import Project="..\..\PowerShell.Common.props" />
<PropertyGroup>
<Description>PowerShell Core's Microsoft.PowerShell.PSReadLine project</Description>
<AssemblyName>Microsoft.PowerShell.PSReadLine</AssemblyName>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\System.Management.Automation\System.Management.Automation.csproj" />
</ItemGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);CORECLR</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugType>portable</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Linux' ">
<DefineConstants>$(DefineConstants);UNIX</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'CodeCoverage' ">
<DebugType>full</DebugType>
</PropertyGroup>
</Project>

View file

@ -1,550 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Management.Automation.Language;
using Microsoft.PowerShell.Internal;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
private int _moveToLineCommandCount;
private int _moveToLineDesiredColumn;
/// <summary>
/// If the input has multiple lines, move to the end of the current line,
/// or if already at the end of the line, move to the end of the input.
/// If the input has a single line, move to the end of the input.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void EndOfLine(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton.LineIsMultiLine())
{
int i = _singleton._current;
for (; i < _singleton._buffer.Length; i++)
{
if (_singleton._buffer[i] == '\n')
{
break;
}
}
_singleton._current = (i == _singleton._current) ? _singleton._buffer.Length : i;
}
else
{
_singleton._current = _singleton._buffer.Length;
}
_singleton.PlaceCursor();
}
/// <summary>
/// If the input has multiple lines, move to the start of the current line,
/// or if already at the start of the line, move to the start of the input.
/// If the input has a single line, move to the start of the input.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void BeginningOfLine(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton.LineIsMultiLine())
{
int i = Math.Max(0, _singleton._current - 1);
for (; i > 0; i--)
{
if (_singleton._buffer[i] == '\n')
{
i += 1;
break;
}
}
_singleton._current = (i == _singleton._current) ? 0 : i;
}
else
{
_singleton._current = 0;
}
_singleton.PlaceCursor();
}
/// <summary>
/// Move the cursor one character to the right. This may move the cursor to the next
/// line of multi-line input.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ForwardChar(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (TryGetArgAsInt(arg, out numericArg, 1))
{
SetCursorPosition(_singleton._current + numericArg);
}
}
/// <summary>
/// Move the cursor one character to the left. This may move the cursor to the previous
/// line of multi-line input.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void BackwardChar(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (TryGetArgAsInt(arg, out numericArg, 1))
{
SetCursorPosition(_singleton._current - numericArg);
}
}
private void MoveToLine(int numericArg)
{
const int endOfLine = int.MaxValue;
_moveToLineCommandCount += 1;
var coords = ConvertOffsetToCoordinates(_current);
if (_moveToLineCommandCount == 1)
{
_moveToLineDesiredColumn =
(_current == _buffer.Length || _buffer[_current] == '\n')
? endOfLine
: coords.X;
}
var topLine = _initialY + Options.ExtraPromptLineCount;
var newY = coords.Y + numericArg;
coords.Y = (short)Math.Max(newY, topLine);
if (_moveToLineDesiredColumn != endOfLine)
{
coords.X = (short)_moveToLineDesiredColumn;
}
var newCurrent = ConvertLineAndColumnToOffset(coords);
if (newCurrent != -1)
{
_current = newCurrent;
if (_moveToLineDesiredColumn == endOfLine)
{
while (_current < _buffer.Length && _buffer[_current] != '\n')
{
_current += 1;
}
}
PlaceCursor();
}
}
/// <summary>
/// Move the cursor to the previous line.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void PreviousLine(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (TryGetArgAsInt(arg, out numericArg, 1))
{
_singleton.MoveToLine(-numericArg);
}
}
/// <summary>
/// Move the cursor to the next line.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void NextLine(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (TryGetArgAsInt(arg, out numericArg, 1))
{
_singleton.MoveToLine(numericArg);
}
}
/// <summary>
/// Move the cursor forward to the start of the next word.
/// Word boundaries are defined by a configurable set of characters.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void NextWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
BackwardWord(key, -numericArg);
return;
}
while (numericArg-- > 0)
{
int i = _singleton.FindNextWordPoint(_singleton.Options.WordDelimiters);
_singleton._current = i;
_singleton.PlaceCursor();
}
}
/// <summary>
/// Move the cursor forward to the end of the current word, or if between words,
/// to the end of the next word. Word boundaries are defined by PowerShell tokens.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ShellNextWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
ShellBackwardWord(key, -numericArg);
return;
}
while (numericArg-- > 0)
{
var token = _singleton.FindToken(_singleton._current, FindTokenMode.Next);
Debug.Assert(token != null, "We'll always find EOF");
_singleton._current = token.Kind == TokenKind.EndOfInput
? _singleton._buffer.Length
: token.Extent.StartOffset;
_singleton.PlaceCursor();
}
}
/// <summary>
/// Move the cursor forward to the end of the current word, or if between words,
/// to the end of the next word. Word boundaries are defined by a configurable
/// set of characters.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ForwardWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
BackwardWord(key, -numericArg);
return;
}
while (numericArg-- > 0)
{
int i = _singleton.FindForwardWordPoint(_singleton.Options.WordDelimiters);
_singleton._current = i;
_singleton.PlaceCursor();
}
}
/// <summary>
/// Move the cursor forward to the start of the next word.
/// Word boundaries are defined by PowerShell tokens.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ShellForwardWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
ShellBackwardWord(key, -numericArg);
return;
}
while (numericArg-- > 0)
{
var token = _singleton.FindToken(_singleton._current, FindTokenMode.CurrentOrNext);
Debug.Assert(token != null, "We'll always find EOF");
_singleton._current = token.Kind == TokenKind.EndOfInput
? _singleton._buffer.Length
: token.Extent.EndOffset;
_singleton.PlaceCursor();
}
}
private static bool CheckIsBound(Action<ConsoleKeyInfo?, object> action)
{
foreach (var entry in _singleton._dispatchTable)
{
if (entry.Value.Action == action)
return true;
}
return false;
}
/// <summary>
/// Move the cursor back to the start of the current word, or if between words,
/// the start of the previous word. Word boundaries are defined by a configurable
/// set of characters.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void BackwardWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
if (CheckIsBound(ForwardWord))
{
ForwardWord(key, -numericArg);
}
else
{
NextWord(key, -numericArg);
}
return;
}
while (numericArg-- > 0)
{
int i = _singleton.FindBackwardWordPoint(_singleton.Options.WordDelimiters);
_singleton._current = i;
_singleton.PlaceCursor();
}
}
/// <summary>
/// Move the cursor back to the start of the current word, or if between words,
/// the start of the previous word. Word boundaries are defined by PowerShell tokens.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ShellBackwardWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
if (CheckIsBound(ShellForwardWord))
{
ShellForwardWord(key, -numericArg);
}
else
{
ShellNextWord(key, -numericArg);
}
return;
}
while (numericArg-- > 0)
{
var token = _singleton.FindToken(_singleton._current, FindTokenMode.Previous);
_singleton._current = (token != null) ? token.Extent.StartOffset : 0;
_singleton.PlaceCursor();
}
}
/// <summary>
/// Go to the matching brace, paren, or square bracket
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void GotoBrace(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton._current >= _singleton._buffer.Length)
{
Ding();
return;
}
_singleton.MaybeParseInput();
Token token = null;
var index = 0;
for (; index < _singleton._tokens.Length; index++)
{
token = _singleton._tokens[index];
if (token.Extent.StartOffset == _singleton._current)
break;
}
TokenKind toMatch;
int direction;
switch (token.Kind)
{
case TokenKind.LParen: toMatch = TokenKind.RParen; direction = 1; break;
case TokenKind.LCurly: toMatch = TokenKind.RCurly; direction = 1; break;
case TokenKind.LBracket: toMatch = TokenKind.RBracket; direction = 1; break;
case TokenKind.RParen: toMatch = TokenKind.LParen; direction = -1; break;
case TokenKind.RCurly: toMatch = TokenKind.LCurly; direction = -1; break;
case TokenKind.RBracket: toMatch = TokenKind.LBracket; direction = -1; break;
default:
// Nothing to match (don't match inside strings/comments)
Ding();
return;
}
var matchCount = 0;
var limit = (direction > 0) ? _singleton._tokens.Length - 1 : -1;
for (; index != limit; index += direction)
{
var t = _singleton._tokens[index];
if (t.Kind == token.Kind)
{
matchCount++;
}
else if (t.Kind == toMatch)
{
matchCount--;
if (matchCount == 0)
{
_singleton._current = t.Extent.StartOffset;
_singleton.PlaceCursor();
return;
}
}
}
Ding();
}
/// <summary>
/// Clear the screen and draw the current line at the top of the screen.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ClearScreen(ConsoleKeyInfo? key = null, object arg = null)
{
var console = _singleton._console;
#if UNIX // TODO: this is not correct, it should only scroll
console.Clear();
_singleton._initialY = 0;
_singleton.Render();
#else
if (_singleton._initialY + console.WindowHeight > console.BufferHeight)
{
var scrollCount = _singleton._initialY - console.WindowTop;
console.ScrollBuffer(scrollCount);
_singleton._initialY -= scrollCount;
console.SetCursorPosition(console.CursorLeft, console.CursorTop - scrollCount);
}
else
{
console.SetWindowPosition(0, _singleton._initialY);
}
#endif
}
// Try to convert the arg to a char, return 0 for failure
private static char TryGetArgAsChar(object arg)
{
if (arg is char)
{
return (char)arg;
}
var s = arg as string;
if (s != null && s.Length == 1)
{
return s[0];
}
return (char)0;
}
/// <summary>
/// Read a character and search forward for the next occurence of that character.
/// If an argument is specified, search forward (or backward if negative) for the
/// nth occurence.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void CharacterSearch(ConsoleKeyInfo? key = null, object arg = null)
{
int occurence = (arg is int) ? (int)arg : 1;
if (occurence < 0)
{
CharacterSearchBackward(key, -occurence);
return;
}
char toFind = TryGetArgAsChar(arg);
if (toFind == (char)0)
{
// Should we prompt?
toFind = ReadKey().KeyChar;
}
for (int i = _singleton._current + 1; i < _singleton._buffer.Length; i++)
{
if (_singleton._buffer[i] == toFind)
{
occurence -= 1;
if (occurence == 0)
{
_singleton._current = i;
_singleton.PlaceCursor();
break;
}
}
}
if (occurence > 0)
{
Ding();
}
}
/// <summary>
/// Read a character and search backward for the next occurence of that character.
/// If an argument is specified, search backward (or forward if negative) for the
/// nth occurence.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void CharacterSearchBackward(ConsoleKeyInfo? key = null, object arg = null)
{
int occurence = (arg is int) ? (int)arg : 1;
if (occurence < 0)
{
CharacterSearch(key, -occurence);
return;
}
char toFind = TryGetArgAsChar(arg);
if (toFind == (char)0)
{
// Should we prompt?
toFind = ReadKey().KeyChar;
}
for (int i = _singleton._current - 1; i >= 0; i--)
{
if (_singleton._buffer[i] == toFind)
{
occurence -= 1;
if (occurence == 0)
{
_singleton._current = i;
_singleton.PlaceCursor();
return;
}
}
}
Ding();
}
}
}

View file

@ -1,326 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
/// <summary>
/// Move the cursor forward to the start of the next word.
/// Word boundaries are defined by a configurable set of characters.
/// </summary>
public static void ViNextWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
ViBackwardWord(key, -numericArg);
return;
}
while (numericArg-- > 0)
{
int i = _singleton.ViFindNextWordPoint(_singleton.Options.WordDelimiters);
if (i >= _singleton._buffer.Length)
{
i += ViEndOfLineFactor;
}
_singleton._current = i;
_singleton.PlaceCursor();
}
}
/// <summary>
/// Move the cursor back to the start of the current word, or if between words,
/// the start of the previous word. Word boundaries are defined by a configurable
/// set of characters.
/// </summary>
public static void ViBackwardWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
ViNextWord(key, -numericArg);
return;
}
while (numericArg-- > 0)
{
int i = _singleton.ViFindPreviousWordPoint(_singleton.Options.WordDelimiters);
_singleton._current = i;
_singleton.PlaceCursor();
}
}
/// <summary>
/// Moves the cursor back to the beginning of the previous word, using only white space as delimiters.
/// </summary>
public static void ViBackwardGlob(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
int i = _singleton._current;
while (numericArg-- > 0)
{
i = _singleton.ViFindPreviousGlob(i - 1);
}
_singleton._current = i;
_singleton.PlaceCursor();
}
/// <summary>
/// Moves to the next word, using only white space as a word delimiter.
/// </summary>
private static void ViNextGlob(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
int i = _singleton._current;
while (numericArg-- > 0)
{
i = _singleton.ViFindNextGlob(i);
}
_singleton._current = Math.Min(i, _singleton._buffer.Length - 1);
_singleton.PlaceCursor();
}
private static void ViEndOfGlob(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
ViEndOfPreviousGlob(key, -numericArg);
return;
}
while (numericArg-- > 0)
{
int i = _singleton.ViFindEndOfGlob();
_singleton._current = i;
_singleton.PlaceCursor();
}
}
private static void ViEndOfPreviousGlob(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
ViEndOfGlob(key, -numericArg);
return;
}
while (numericArg-- > 0)
{
int i = _singleton.ViFindEndOfPreviousGlob();
_singleton._current = i;
_singleton.PlaceCursor();
}
}
/// <summary>
/// Returns 0 if the cursor is allowed to go past the last character in the line, -1 otherwise.
/// </summary>
/// <seealso cref="ForwardChar"/>
private static int ViEndOfLineFactor
{
get
{
if (_singleton._dispatchTable == _viCmdKeyMap)
{
return -1;
}
return 0;
}
}
/// <summary>
/// Move the cursor to the end of the input.
/// </summary>
public static void MoveToEndOfLine(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton._current = Math.Max(0, _singleton._buffer.Length + ViEndOfLineFactor);
_singleton.PlaceCursor();
}
/// <summary>
/// Move the cursor forward to the end of the current word, or if between words,
/// to the end of the next word. Word boundaries are defined by a configurable
/// set of characters.
/// </summary>
public static void NextWordEnd(ConsoleKeyInfo? key = null, object arg = null)
{
int qty = (arg is int) ? (int)arg : 1;
for (; qty > 0 && _singleton._current < _singleton._buffer.Length - 1; qty--)
{
int i = _singleton.ViFindNextWordEnd(_singleton.Options.WordDelimiters);
_singleton._current = i;
_singleton.PlaceCursor();
}
}
/// <summary>
/// Move to the column indicated by arg.
/// </summary>
public static void GotoColumn(ConsoleKeyInfo? key = null, object arg = null)
{
int col = (arg is int) ? (int) arg : -1;
if (col < 0 ) {
Ding();
return;
}
if (col < _singleton._buffer.Length + ViEndOfLineFactor)
{
_singleton._current = Math.Min(col, _singleton._buffer.Length) - 1;
}
else
{
_singleton._current = _singleton._buffer.Length + ViEndOfLineFactor;
Ding();
}
_singleton.PlaceCursor();
}
/// <summary>
/// Move the cursor to the first non-blank character in the line.
/// </summary>
public static void GotoFirstNonBlankOfLine(ConsoleKeyInfo? key = null, object arg = null)
{
for (int i = 0; i < _singleton._buffer.Length; i++)
{
if (!Char.IsWhiteSpace(_singleton._buffer[i]))
{
_singleton._current = i;
_singleton.PlaceCursor();
return;
}
}
}
/// <summary>
/// Similar to <see cref="GotoBrace"/>, but is character based instead of token based.
/// </summary>
public static void ViGotoBrace(ConsoleKeyInfo? key = null, object arg = null)
{
int i = _singleton.ViFindBrace(_singleton._current);
if (i == _singleton._current)
{
Ding();
return;
}
_singleton._current = i;
_singleton.PlaceCursor();
}
private int ViFindBrace(int i)
{
switch (_buffer[i])
{
case '{':
return ViFindForward(i, '}', withoutPassing: '{');
case '[':
return ViFindForward(i, ']', withoutPassing: '[');
case '(':
return ViFindForward(i, ')', withoutPassing: '(');
case '}':
return ViFindBackward(i, '{', withoutPassing: '}');
case ']':
return ViFindBackward(i, '[', withoutPassing: ']');
case ')':
return ViFindBackward(i, '(', withoutPassing: ')');
default:
return i;
}
}
private int ViFindBackward(int start, char target, char withoutPassing)
{
if (start == 0)
{
return start;
}
int i = start - 1;
int withoutPassingCount = 0;
while (i != 0 && !(_buffer[i] == target && withoutPassingCount == 0))
{
if (_buffer[i] == withoutPassing)
{
withoutPassingCount++;
}
if (_buffer[i] == target)
{
withoutPassingCount--;
}
i--;
}
if (_buffer[i] == target && withoutPassingCount == 0)
{
return i;
}
return start;
}
private int ViFindForward(int start, char target, char withoutPassing)
{
if (IsAtEndOfLine(start))
{
return start;
}
int i = start + 1;
int withoutPassingCount = 0;
while (!IsAtEndOfLine(i) && !(_buffer[i] == target && withoutPassingCount == 0))
{
if (_buffer[i] == withoutPassing)
{
withoutPassingCount++;
}
if (_buffer[i] == target)
{
withoutPassingCount--;
}
i++;
}
if (_buffer[i] == target && withoutPassingCount == 0)
{
return i;
}
return start;
}
}
}

View file

@ -1,403 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Management.Automation;
using System.Reflection;
using System.Threading;
using Microsoft.PowerShell.Internal;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
private readonly PSConsoleReadlineOptions _options;
private PSConsoleReadlineOptions Options
{
get { return _options; }
}
private void SetOptionsInternal(SetPSReadlineOption options)
{
if (options.ContinuationPrompt != null)
{
Options.ContinuationPrompt = options.ContinuationPrompt;
}
if (options._continuationPromptForegroundColor.HasValue)
{
Options.ContinuationPromptForegroundColor = options.ContinuationPromptForegroundColor;
}
if (options._continuationPromptBackgroundColor.HasValue)
{
Options.ContinuationPromptBackgroundColor = options.ContinuationPromptBackgroundColor;
}
if (options._emphasisBackgroundColor.HasValue)
{
Options.EmphasisBackgroundColor = options.EmphasisBackgroundColor;
}
if (options._emphasisForegroundColor.HasValue)
{
Options.EmphasisForegroundColor = options.EmphasisForegroundColor;
}
if (options._errorBackgroundColor.HasValue)
{
Options.ErrorBackgroundColor = options.ErrorBackgroundColor;
}
if (options._errorForegroundColor.HasValue)
{
Options.ErrorForegroundColor = options.ErrorForegroundColor;
}
if (options._historyNoDuplicates.HasValue)
{
Options.HistoryNoDuplicates = options.HistoryNoDuplicates;
}
if (options._historySearchCursorMovesToEnd.HasValue)
{
Options.HistorySearchCursorMovesToEnd = options.HistorySearchCursorMovesToEnd;
}
if (options._addToHistoryHandlerSpecified)
{
Options.AddToHistoryHandler = options.AddToHistoryHandler;
}
if (options._commandValidationHandlerSpecified)
{
Options.CommandValidationHandler = options.CommandValidationHandler;
}
if (options._maximumHistoryCount.HasValue)
{
Options.MaximumHistoryCount = options.MaximumHistoryCount;
if (_history != null)
{
var newHistory = new HistoryQueue<HistoryItem>(Options.MaximumHistoryCount);
while (_history.Count > Options.MaximumHistoryCount)
{
_history.Dequeue();
}
while (_history.Count > 0)
{
newHistory.Enqueue(_history.Dequeue());
}
_history = newHistory;
_currentHistoryIndex = _history.Count;
}
}
if (options._maximumKillRingCount.HasValue)
{
Options.MaximumKillRingCount = options.MaximumKillRingCount;
// TODO - make _killRing smaller
}
if (options._editMode.HasValue)
{
Options.EditMode = options.EditMode;
// Switching/resetting modes - clear out chord dispatch table
_chordDispatchTable.Clear();
SetDefaultBindings(Options.EditMode);
}
if (options._showToolTips.HasValue)
{
Options.ShowToolTips = options.ShowToolTips;
}
if (options._extraPromptLineCount.HasValue)
{
Options.ExtraPromptLineCount = options.ExtraPromptLineCount;
}
if (options._dingTone.HasValue)
{
Options.DingTone = options.DingTone;
}
if (options._dingDuration.HasValue)
{
Options.DingDuration = options.DingDuration;
}
if (options._bellStyle.HasValue)
{
Options.BellStyle = options.BellStyle;
}
if (options._completionQueryItems.HasValue)
{
Options.CompletionQueryItems = options.CompletionQueryItems;
}
if (options.WordDelimiters != null)
{
Options.WordDelimiters = options.WordDelimiters;
}
if (options._historySearchCaseSensitive.HasValue)
{
Options.HistorySearchCaseSensitive = options.HistorySearchCaseSensitive;
}
if (options._historySaveStyle.HasValue)
{
Options.HistorySaveStyle = options.HistorySaveStyle;
}
#region vi
if (options._viModeIndicator.HasValue)
{
Options.ViModeIndicator = options.ViModeIndicator;
}
#endregion
if (options.HistorySavePath != null)
{
Options.HistorySavePath = options.HistorySavePath;
if (_historyFileMutex != null)
{
_historyFileMutex.Dispose();
}
_historyFileMutex = new Mutex(false, GetHistorySaveFileMutexName());
_historyFileLastSavedSize = 0;
}
if (options.ResetTokenColors)
{
Options.ResetColors();
}
if (options._tokenKind.HasValue)
{
if (options._foregroundColor.HasValue)
{
Options.SetForegroundColor(options.TokenKind, options.ForegroundColor);
}
if (options._backgroundColor.HasValue)
{
Options.SetBackgroundColor(options.TokenKind, options.BackgroundColor);
}
}
}
private void SetKeyHandlerInternal(string[] keys, Action<ConsoleKeyInfo?, object> handler, string briefDescription, string longDescription, ScriptBlock scriptBlock)
{
foreach (var key in keys)
{
var chord = ConsoleKeyChordConverter.Convert(key);
if (chord.Length == 1)
{
_dispatchTable[chord[0]] = MakeKeyHandler(handler, briefDescription, longDescription, scriptBlock);
}
else
{
_dispatchTable[chord[0]] = MakeKeyHandler(Chord, "ChordFirstKey");
Dictionary<ConsoleKeyInfo, KeyHandler> secondDispatchTable;
if (!_chordDispatchTable.TryGetValue(chord[0], out secondDispatchTable))
{
secondDispatchTable = new Dictionary<ConsoleKeyInfo, KeyHandler>();
_chordDispatchTable[chord[0]] = secondDispatchTable;
}
secondDispatchTable[chord[1]] = MakeKeyHandler(handler, briefDescription, longDescription, scriptBlock);
}
}
}
private void RemoveKeyHandlerInternal(string[] keys)
{
foreach (var key in keys)
{
var chord = ConsoleKeyChordConverter.Convert(key);
if (chord.Length == 1)
{
_dispatchTable.Remove(chord[0]);
}
else
{
Dictionary<ConsoleKeyInfo, KeyHandler> secondDispatchTable;
if (_chordDispatchTable.TryGetValue(chord[0], out secondDispatchTable))
{
secondDispatchTable.Remove(chord[1]);
if (secondDispatchTable.Count == 0)
{
_dispatchTable.Remove(chord[0]);
}
}
}
}
}
/// <summary>
/// Helper function for the Set-PSReadlineOption cmdlet.
/// </summary>
public static void SetOptions(SetPSReadlineOption options)
{
_singleton.SetOptionsInternal(options);
}
/// <summary>
/// Helper function for the Get-PSReadlineOption cmdlet.
/// </summary>
public static PSConsoleReadlineOptions GetOptions()
{
// Should we copy? It doesn't matter much, everything can be tweaked from
// the cmdlet anyway.
return _singleton._options;
}
class CustomHandlerException : Exception
{
internal CustomHandlerException(Exception innerException)
: base("", innerException)
{
}
}
/// <summary>
/// Helper function for the Set-PSReadlineKeyHandler cmdlet.
/// </summary>
public static void SetKeyHandler(string[] key, ScriptBlock scriptBlock, string briefDescription, string longDescription)
{
Action<ConsoleKeyInfo?, object> handler = (k, arg) =>
{
try
{
scriptBlock.Invoke(k, arg);
}
catch (Exception e)
{
throw new CustomHandlerException(e);
}
};
_singleton.SetKeyHandlerInternal(key, handler, briefDescription, longDescription, scriptBlock);
}
/// <summary>
/// Helper function for the Set-PSReadlineKeyHandler cmdlet.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
public static void SetKeyHandler(string[] key, Action<ConsoleKeyInfo?, object> handler, string briefDescription, string longDescription)
{
_singleton.SetKeyHandlerInternal(key, handler, briefDescription, longDescription, null);
}
/// <summary>
/// Helper function for the Remove-PSReadlineKeyHandler cmdlet.
/// </summary>
/// <param name="key"></param>
public static void RemoveKeyHandler(string[] key)
{
_singleton.RemoveKeyHandlerInternal(key);
}
/// <summary>
/// Helper function for the Get-PSReadlineKeyHandler cmdlet.
/// </summary>
/// <returns></returns>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static IEnumerable<Microsoft.PowerShell.KeyHandler> GetKeyHandlers(bool includeBound = true, bool includeUnbound = false)
{
var boundFunctions = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var entry in _singleton._dispatchTable)
{
if (entry.Value.BriefDescription == "Ignore"
|| entry.Value.BriefDescription == "ChordFirstKey")
{
continue;
}
boundFunctions.Add(entry.Value.BriefDescription);
if (includeBound)
{
yield return new Microsoft.PowerShell.KeyHandler
{
Key = entry.Key.ToGestureString(),
Function = entry.Value.BriefDescription,
Description = entry.Value.LongDescription,
};
}
}
// Added to support vi command mode mappings
if (_singleton._options.EditMode == EditMode.Vi)
{
foreach (var entry in _viCmdKeyMap)
{
if (entry.Value.BriefDescription == "Ignore"
|| entry.Value.BriefDescription == "ChordFirstKey")
{
continue;
}
boundFunctions.Add(entry.Value.BriefDescription);
if (includeBound)
{
yield return new Microsoft.PowerShell.KeyHandler
{
Key = "<" + entry.Key.ToGestureString() + ">",
Function = entry.Value.BriefDescription,
Description = entry.Value.LongDescription,
};
}
}
}
foreach( var entry in _singleton._chordDispatchTable )
{
foreach( var secondEntry in entry.Value )
{
boundFunctions.Add( secondEntry.Value.BriefDescription );
if (includeBound)
{
yield return new Microsoft.PowerShell.KeyHandler
{
Key = entry.Key.ToGestureString() + "," + secondEntry.Key.ToGestureString(),
Function = secondEntry.Value.BriefDescription,
Description = secondEntry.Value.LongDescription,
};
}
}
}
// Added to support vi command mode chorded mappings
if (_singleton._options.EditMode == EditMode.Vi)
{
foreach (var entry in _viCmdChordTable)
{
foreach (var secondEntry in entry.Value)
{
if (secondEntry.Value.BriefDescription == "Ignore")
{
continue;
}
boundFunctions.Add(secondEntry.Value.BriefDescription);
if (includeBound)
{
yield return new Microsoft.PowerShell.KeyHandler
{
Key = "<" + entry.Key.ToGestureString() + "," + secondEntry.Key.ToGestureString() + ">",
Function = secondEntry.Value.BriefDescription,
Description = secondEntry.Value.LongDescription
};
}
}
}
}
if (includeUnbound)
{
// SelfInsert isn't really unbound, but we don't want UI to show it that way
boundFunctions.Add("SelfInsert");
var methods = typeof (PSConsoleReadLine).GetMethods(BindingFlags.Public | BindingFlags.Static);
foreach (var method in methods)
{
var parameters = method.GetParameters();
if (parameters.Length != 2 ||
parameters[0].ParameterType != typeof (ConsoleKeyInfo?) ||
parameters[1].ParameterType != typeof (object))
{
continue;
}
if (!boundFunctions.Contains(method.Name))
{
yield return new Microsoft.PowerShell.KeyHandler
{
Key = "Unbound",
Function = method.Name,
Description = null,
};
}
}
}
}
}
}

View file

@ -1,17 +0,0 @@
@{
RootModule = 'PSReadLine.psm1'
NestedModules = @("Microsoft.PowerShell.PSReadLine.dll")
ModuleVersion = '1.2'
GUID = '5714753b-2afd-4492-a5fd-01d9e2cff8b5'
Author = 'Microsoft Corporation'
CompanyName = 'Microsoft Corporation'
Copyright = 'Copyright (c) Microsoft Corporation. All rights reserved.'
Description = 'Great command line editing in the PowerShell console host'
PowerShellVersion = '3.0'
DotNetFrameworkVersion = '4.0'
CLRVersion = '4.0'
FunctionsToExport = 'PSConsoleHostReadline'
CmdletsToExport = 'Get-PSReadlineKeyHandler','Set-PSReadlineKeyHandler','Remove-PSReadlineKeyHandler',
'Get-PSReadlineOption','Set-PSReadlineOption'
HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855966'
}

View file

@ -1,5 +0,0 @@
function PSConsoleHostReadline
{
Microsoft.PowerShell.Core\Set-StrictMode -Off
[Microsoft.PowerShell.PSConsoleReadLine]::ReadLine($host.Runspace, $ExecutionContext)
}

File diff suppressed because it is too large Load diff

View file

@ -1,720 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="https://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AcceptLineDescription" xml:space="preserve">
<value>Accept the input or move to the next line if input is missing a closing token.</value>
</data>
<data name="AddLineDescription" xml:space="preserve">
<value>Move the cursor to the next line without attempting to execute the input</value>
</data>
<data name="BackwardCharDescription" xml:space="preserve">
<value>Move the cursor back one character</value>
</data>
<data name="BackwardDeleteCharDescription" xml:space="preserve">
<value>Delete the character before the cursor</value>
</data>
<data name="BackwardDeleteLineDescription" xml:space="preserve">
<value>Delete text from the cursor to the start of the line</value>
</data>
<data name="BackwardKillLineDescription" xml:space="preserve">
<value>Move the text from the cursor to the beginning of the line to the kill ring</value>
</data>
<data name="BeginningOfHistoryDescription" xml:space="preserve">
<value>Move to the first item in the history</value>
</data>
<data name="BeginningOfLineDescription" xml:space="preserve">
<value>Move the cursor to the beginning of the line</value>
</data>
<data name="CancelLineDescription" xml:space="preserve">
<value>Abort editing the current line and re-evaluate the prompt</value>
</data>
<data name="ClearKillRingDescription" xml:space="preserve">
<value>Remove all items from the kill ring</value>
</data>
<data name="ClearHistoryDescription" xml:space="preserve">
<value>Remove all items from the command line history (not PowerShell history)</value>
</data>
<data name="CompleteDescription" xml:space="preserve">
<value>Complete the input if there is a single completion, otherwise complete the input with common prefix for all completions. Show possible completions if pressed a second time.</value>
</data>
<data name="DeleteCharDescription" xml:space="preserve">
<value>Delete the character under the cursor</value>
</data>
<data name="ShellBackwardWordDescription" xml:space="preserve">
<value>Move the cursor to the beginning of the current or previous token or start of the line</value>
</data>
<data name="EmacsCtrlXDescription" xml:space="preserve">
<value>String is not used in the UI</value>
</data>
<data name="EmacsMetaDescription" xml:space="preserve">
<value>String is not used in the UI</value>
</data>
<data name="EndOfHistoryDescription" xml:space="preserve">
<value>Move to the last item (the current input) in the history</value>
</data>
<data name="EndOfLineDescription" xml:space="preserve">
<value>Move the cursor to the end of the line</value>
</data>
<data name="ExchangePointAndMarkDescription" xml:space="preserve">
<value>Mark the location of the cursor and move the cursor to the position of the previous mark</value>
</data>
<data name="ForwardCharDescription" xml:space="preserve">
<value>Move the cursor forward one character</value>
</data>
<data name="ForwardDeleteLineDescription" xml:space="preserve">
<value>Delete text from the cursor to the end of the line</value>
</data>
<data name="ShellForwardWordDescription" xml:space="preserve">
<value>Move the cursor to the beginning of the next token or end of line</value>
</data>
<data name="HistorySearchBackwardDescription" xml:space="preserve">
<value>Search for the previous item in the history that starts with the current input - like PreviousHistory if the input is empty</value>
</data>
<data name="HistorySearchForwardDescription" xml:space="preserve">
<value>Search for the next item in the history that starts with the current input - like NextHistory if the input is empty</value>
</data>
<data name="IgnoreDescription" xml:space="preserve">
<value>String is not used in the UI</value>
</data>
<data name="ShellBackwardKillWordDescription" xml:space="preserve">
<value>Move the text from the cursor to the start of the current or previous token to the kill ring</value>
</data>
<data name="KillLineDescription" xml:space="preserve">
<value>Move the text from the cursor to the end of the input to the kill ring</value>
</data>
<data name="ShellKillWordDescription" xml:space="preserve">
<value>Move the text from the cursor to the end of the current or next token to the kill ring</value>
</data>
<data name="NextHistoryDescription" xml:space="preserve">
<value>Replace the input with the next item in the history</value>
</data>
<data name="PasteDescription" xml:space="preserve">
<value>Paste text from the system clipboard</value>
</data>
<data name="PossibleCompletionsDescription" xml:space="preserve">
<value>Display the possible completions without changing the input</value>
</data>
<data name="PreviousHistoryDescription" xml:space="preserve">
<value>Replace the input with the previous item in the history</value>
</data>
<data name="RedoDescription" xml:space="preserve">
<value>Redo an undo</value>
</data>
<data name="RevertLineDescription" xml:space="preserve">
<value>Equivalent to undo all edits (clears the line except lines imported from history)</value>
</data>
<data name="SetMarkDescription" xml:space="preserve">
<value>Mark the location of the cursor</value>
</data>
<data name="TabCompleteNextDescription" xml:space="preserve">
<value>Complete the input using the next completion</value>
</data>
<data name="TabCompletePreviousDescription" xml:space="preserve">
<value>Complete the input using the previous completion</value>
</data>
<data name="UndoDescription" xml:space="preserve">
<value>Undo a previous edit</value>
</data>
<data name="YankDescription" xml:space="preserve">
<value>Copy the text from the current kill ring position to the input</value>
</data>
<data name="YankPopDescription" xml:space="preserve">
<value>Replace the previously yanked text with the text from the next kill ring position</value>
</data>
<data name="StartOutOfRange" xml:space="preserve">
<value>'start' cannot be less than zero or greater than the length of the buffer</value>
</data>
<data name="ReplacementLengthTooBig" xml:space="preserve">
<value>length is too big</value>
</data>
<data name="DisplayAllPossibilities" xml:space="preserve">
<value>Display all {0} possibilities? (y or n) _</value>
</data>
<data name="ClearScreenDescription" xml:space="preserve">
<value>Clear the screen and redraw the current line at the top of the screen</value>
</data>
<data name="GotoBraceDescription" xml:space="preserve">
<value>Go to matching brace</value>
</data>
<data name="AbortDescription" xml:space="preserve">
<value>Abort the current operation, e.g. incremental history search</value>
</data>
<data name="ForwardSearchHistoryDescription" xml:space="preserve">
<value>Search history forward interactively</value>
</data>
<data name="ReverseSearchHistoryDescription" xml:space="preserve">
<value>Search history backwards interactively</value>
</data>
<data name="BackwardKillWordDescription" xml:space="preserve">
<value>Move the text from the start of the current or previous word to the cursor to the kill ring</value>
</data>
<data name="BackwardWordDescription" xml:space="preserve">
<value>Move the cursor to the beginning of the current or previous word</value>
</data>
<data name="ForwardWordDescription" xml:space="preserve">
<value>Move the cursor forward to the end of the current word, or if between words, to the end of the next word. </value>
</data>
<data name="KillWordDescription" xml:space="preserve">
<value>Move the text from the cursor to the end of the current or next word to the kill ring</value>
</data>
<data name="NextWordDescription" xml:space="preserve">
<value>Move the cursor forward to the start of the next word</value>
</data>
<data name="UnixWordRuboutDescription" xml:space="preserve">
<value>Move the text from the cursor to the start of the current or previous whitespace delimited word to the kill ring</value>
</data>
<data name="CharacterSearchBackwardDescription" xml:space="preserve">
<value>Read a character and move the cursor to the previous occurence of that character</value>
</data>
<data name="CharacterSearchDescription" xml:space="preserve">
<value>Read a character and move the cursor to the next occurence of that character</value>
</data>
<data name="DigitArgumentDescription" xml:space="preserve">
<value>Start or accumulate a numeric argument to other functions</value>
</data>
<data name="YankLastArgDescription" xml:space="preserve">
<value>Copy the text of the last argument to the input</value>
</data>
<data name="YankNthArgDescription" xml:space="preserve">
<value>Copy the text of the first argument to the input</value>
</data>
<data name="AcceptAndGetNextDescription" xml:space="preserve">
<value>Accept the current line and recall the next line from history after the current line finishes executing</value>
</data>
<data name="KeyIsUnbound" xml:space="preserve">
<value>Key is unbound</value>
</data>
<data name="SelfInsertDescription" xml:space="preserve">
<value>Insert the key typed</value>
</data>
<data name="ShowKeyBindingsDescription" xml:space="preserve">
<value>Show all key bindings</value>
</data>
<data name="WhatIsKeyDescription" xml:space="preserve">
<value>Show the key binding for the next chord entered</value>
</data>
<data name="CopyDescription" xml:space="preserve">
<value>Copy selected region to the system clipboard. If no region is selected, copy the whole line</value>
</data>
<data name="CutDescription" xml:space="preserve">
<value>Delete selected region placing deleted text in the system clipboard</value>
</data>
<data name="KillRegionDescription" xml:space="preserve">
<value>Kill the text between the cursor and the mark</value>
</data>
<data name="SelectBackwardCharDescription" xml:space="preserve">
<value>Adjust the current selection to include the previous character</value>
</data>
<data name="SelectBackwardWordDescription" xml:space="preserve">
<value>Adjust the current selection to include the previous word</value>
</data>
<data name="SelectForwardCharDescription" xml:space="preserve">
<value>Adjust the current selection to include the next character</value>
</data>
<data name="SelectForwardWordDescription" xml:space="preserve">
<value>Adjust the current selection to include the next word using ForwardWord</value>
</data>
<data name="SelectNextWordDescription" xml:space="preserve">
<value>Adjust the current selection to include the next word</value>
</data>
<data name="SelectShellBackwardWordDescription" xml:space="preserve">
<value>Adjust the current selection to include the previous word using ShellBackwardWord</value>
</data>
<data name="SelectShellForwardWordDescription" xml:space="preserve">
<value>Adjust the current selection to include the next word using ShellForwardWord</value>
</data>
<data name="CaptureScreenDescription" xml:space="preserve">
<value>Allows you to select multiple lines from the console using Shift+UpArrow/DownArrow and copy the selected lines to clipboard by pressing Enter.</value>
</data>
<data name="InvokePromptDescription" xml:space="preserve">
<value>Erases the current prompt and calls the prompt function to redisplay the prompt</value>
</data>
<data name="ScrollDisplayDownDescription" xml:space="preserve">
<value>Scroll the display down one screen</value>
</data>
<data name="ScrollDisplayDownLineDescription" xml:space="preserve">
<value>Scroll the display down one line</value>
</data>
<data name="ScrollDisplayToCursorDescription" xml:space="preserve">
<value>Scroll the display to the cursor</value>
</data>
<data name="ScrollDisplayTopDescription" xml:space="preserve">
<value>Scroll the display to the top</value>
</data>
<data name="ScrollDisplayUpDescription" xml:space="preserve">
<value>Scroll the display up one screen</value>
</data>
<data name="ScrollDisplayUpLineDescription" xml:space="preserve">
<value>Scroll the display up one line</value>
</data>
<data name="SelectShellNextWordDescription" xml:space="preserve">
<value>Adjust the current selection to include the next word using ShellNextWord</value>
</data>
<data name="ShellNextWordDescription" xml:space="preserve">
<value>Move the cursor to the end of the current token</value>
</data>
<data name="SelectBackwardsLineDescription" xml:space="preserve">
<value>Adjust the current selection to include from the cursor to the end of the line</value>
</data>
<data name="SelectLineDescription" xml:space="preserve">
<value>Adjust the current selection to include from the cursor to the start of the line</value>
</data>
<data name="SelectAllDescription" xml:space="preserve">
<value>Select the entire line. Moves the cursor to the end of the line</value>
</data>
<data name="CopyOrCancelLineDescription" xml:space="preserve">
<value>Either copy selected text to the clipboard, or if no text is selected, cancel editing the line with CancelLine.</value>
</data>
<data name="MenuCompleteDescription" xml:space="preserve">
<value>Complete the input if there is a single completion, otherwise complete the input by selecting from a menu of possible completions.</value>
</data>
<data name="OopsAnErrorMessage1" xml:space="preserve">
<value>
Oops, something went wrong. Please report this bug with the details below.
Report on GitHub: https://github.com/lzybkr/PSReadLine/issues/new</value>
</data>
<data name="OopsAnErrorMessage2" xml:space="preserve">
<value>-----------------------------------------------------------------------
Last {0} Keys:
{1}
Exception:
{2}
-----------------------------------------------------------------------</value>
</data>
<data name="NextLineDescription" xml:space="preserve">
<value>Move the cursor to the next line if the input has multiple lines.</value>
</data>
<data name="PreviousLineDescription" xml:space="preserve">
<value>Move the cursor to the previous line if the input has multiple lines.</value>
</data>
<data name="CommandNotFoundError" xml:space="preserve">
<value>Command '{0}' cannot be found.</value>
</data>
<data name="ValidateAndAcceptLineDescription" xml:space="preserve">
<value>Accept the input or move to the next line if input is missing a closing token.
If there are other parse errors, unresolved commands, or incorrect parameters, show the error and continue editing.</value>
</data>
<data name="DeleteCharOrExitDescription" xml:space="preserve">
<value>Delete the character under the cursor, or if the line is empty, exit the process.</value>
</data>
<data name="CantTranslateKey" xml:space="preserve">
<value>Unable to translate '{0}' to virtual key code: {1}.</value>
</data>
<data name="ChordWithTooManyKeys" xml:space="preserve">
<value>Chord can have at most two keys.</value>
</data>
<data name="InvalidModifier" xml:space="preserve">
<value>Duplicate or invalid modifier token '{0}' for key '{1}'.</value>
</data>
<data name="InvalidSequence" xml:space="preserve">
<value>Invalid sequence '{0}'.</value>
</data>
<data name="UnrecognizedKey" xml:space="preserve">
<value>Unrecognized key '{0}'. Please use a character literal or a well-known key name from the System.ConsoleKey enumeration.</value>
</data>
<data name="ViAcceptLineDescription" xml:space="preserve">
<value>Accept the line and switch to Vi's insert mode.</value>
</data>
<data name="BackwardDeleteWordDescription" xml:space="preserve">
<value>Delete the previous word in the line.</value>
</data>
<data name="ViCommandModeDescription" xml:space="preserve">
<value>Switch to VI's command mode.</value>
</data>
<data name="MoveToEndOfLineDescription" xml:space="preserve">
<value>Move to the end of the line.</value>
</data>
<data name="ViInsertWithAppendDescription" xml:space="preserve">
<value>Switch to insert mode, appending at the current line position.</value>
</data>
<data name="SwapCharactersDescription" xml:space="preserve">
<value>Swap the current character with the character before it.</value>
</data>
<data name="RepeatLastSearchDescription" xml:space="preserve">
<value>Repeats the last search.</value>
</data>
<data name="SearchBackwardCharDescription" xml:space="preserve">
<value>Searches backward for the prescribed character.</value>
</data>
<data name="SearchDescription" xml:space="preserve">
<value>Searches for the prescribed character in the prescribed direction.</value>
</data>
<data name="ViAppendAtEndDescription" xml:space="preserve">
<value>Switches to insert mode after positioning the cursor past the end of the line.</value>
</data>
<data name="DeleteLineToFirstCharDescription" xml:space="preserve">
<value>Deletes all of the line except for leading whitespace.</value>
</data>
<data name="BackwardReplaceCharDescription" xml:space="preserve">
<value>Replaces the character in front of the cursor.</value>
</data>
<data name="ViBackwardReplaceLineDescription" xml:space="preserve">
<value>Replaces the line left of the cursor and all of the way to the beginning.</value>
</data>
<data name="ViBackwardReplaceLineToFirstCharDescription" xml:space="preserve">
<value>Replaces the line left of the cursor and all but one character to the beginning of the line.</value>
</data>
<data name="PrependAndAcceptDescription" xml:space="preserve">
<value>Inserts the entered character at the beginning and accepts the line.</value>
</data>
<data name="DeleteBraceDescription" xml:space="preserve">
<value>Deletes all characters between the cursor and the matching brace.</value>
</data>
<data name="DeleteLineDescription" xml:space="preserve">
<value>Deletes the current line.</value>
</data>
<data name="DeleteToEndDescription" xml:space="preserve">
<value>Deletes from the cursor to the end of the line.</value>
</data>
<data name="DeleteToEndOfWordDescription" xml:space="preserve">
<value>Deletes from the cursor to the end of the current word.</value>
</data>
<data name="DeleteWordDescription" xml:space="preserve">
<value>Deletes the current word.</value>
</data>
<data name="GotoFirstNonBlankOfLineDescription" xml:space="preserve">
<value>Positions the cursor at the first non-blank character.</value>
</data>
<data name="NextWordEndDescription" xml:space="preserve">
<value>Moves the cursor forward to the end of the next word.</value>
</data>
<data name="GotoColumnDescription" xml:space="preserve">
<value>Moves the cursor to the prescribed column.</value>
</data>
<data name="ViInsertModeDescription" xml:space="preserve">
<value>Switches to insert mode.</value>
</data>
<data name="ViInsertAtBeginingDescription" xml:space="preserve">
<value>Moves the cursor to the beginning of the line and switches to insert mode.</value>
</data>
<data name="ViInsertAtEndDescription" xml:space="preserve">
<value>Moves the cursor to the end of the line and switches to insert mode.</value>
</data>
<data name="ViInsertWithDeleteDescription" xml:space="preserve">
<value>Deletes the current character and switches to insert mode.</value>
</data>
<data name="InvertCaseDescription" xml:space="preserve">
<value>Inverts the case of the current character and advances the cursor.</value>
</data>
<data name="RepeatLastCommandDescription" xml:space="preserve">
<value>Repeats the last modification command.</value>
</data>
<data name="RepeatSearchBackwardDescription" xml:space="preserve">
<value>Repeat the last search, but in the opposite direction.</value>
</data>
<data name="RepeatSearchDescription" xml:space="preserve">
<value>Repeat the last search.</value>
</data>
<data name="ViReplaceBraceDescription" xml:space="preserve">
<value>Replace all characters between the current brace character and it's matching partner.</value>
</data>
<data name="ReplaceCharDescription" xml:space="preserve">
<value>Replace the current character with the next set of characters typed.</value>
</data>
<data name="ReplaceCharInPlaceDescription" xml:space="preserve">
<value>Replace the current character with only one character.</value>
</data>
<data name="ViReplaceLineDescription" xml:space="preserve">
<value>Repace the current line with the next set of characters typed.</value>
</data>
<data name="ViReplaceToEndDescription" xml:space="preserve">
<value>Replace the characters from the cursor position to the end of the line.</value>
</data>
<data name="ViReplaceUntilEscDescription" xml:space="preserve">
<value>Replace the current character until an escape is entered or the line is accepted.</value>
</data>
<data name="ViReplaceWordDescription" xml:space="preserve">
<value>Replace the current word.</value>
</data>
<data name="InsertCharacterDescription" xml:space="preserve">
<value>Delete the current character and insert the next character.</value>
</data>
<data name="ViSearchHistoryBackwardDescription" xml:space="preserve">
<value>Starts a new search backward in the history.</value>
</data>
<data name="ViTransposeCharsDescription" xml:space="preserve">
<value>Transposes the current character with the next character in the line.</value>
</data>
<data name="UndoAllDescription" xml:space="preserve">
<value>Undoes all commands for this line.</value>
</data>
<data name="SearchForwardDescription" xml:space="preserve">
<value>Prompts for a search string and initiates a search upon AcceptLine.</value>
</data>
<data name="RepeatLastCharSearchBackwardsDescription" xml:space="preserve">
<value>Repeat the last recorded character search in the opposite direction.</value>
</data>
<data name="RepeatLastCharSearchDescription" xml:space="preserve">
<value>Repeat the last recorded character search.</value>
</data>
<data name="SearchCharBackwardDescription" xml:space="preserve">
<value>Move to the previous occurrence of the specified character.</value>
</data>
<data name="SearchCharBackwardWithBackoffDescription" xml:space="preserve">
<value>Move to the previous occurrence of the specified character and then forward one character.</value>
</data>
<data name="SearchCharDescription" xml:space="preserve">
<value>Move to the next occurrence of the specified character.</value>
</data>
<data name="SearchCharWithBackoffDescription" xml:space="preserve">
<value>Move to he next occurrence of the specified character and then back one character.</value>
</data>
<data name="ViBackwardReplaceWordDescription" xml:space="preserve">
<value>Replace the previous word.</value>
</data>
<data name="ViBackwardWordDescription" xml:space="preserve">
<value>Delete backward to the beginning of the previous word, as delimited by white space and common delimiters, and enter insert mode.</value>
</data>
<data name="PasteAfterDescription" xml:space="preserve">
<value>Write the contents of the local clipboard after the cursor.</value>
</data>
<data name="ViNextWordDescription" xml:space="preserve">
<value>Move the cursor to the beginning of the next word, as delimited by white space and common delimiters.</value>
</data>
<data name="ViBackwardGlobDescription" xml:space="preserve">
<value>Move the cursor to the beginning of the previous word, as delimited by white space.</value>
</data>
<data name="ViEndOfGlobDescription" xml:space="preserve">
<value>Move the cursor to the end this word, as delimited by white space.</value>
</data>
<data name="PasteBeforeDescription" xml:space="preserve">
<value>Write the contents of the local clipboard before the cursor.</value>
</data>
<data name="ViNextGlobDescription" xml:space="preserve">
<value>Move the cursor to the beginning of the next word, as delimited by white space.</value>
</data>
<data name="ViGotoBraceDescription" xml:space="preserve">
<value>Move the cursor to the matching brace.</value>
</data>
<data name="ViBackwardDeleteGlobDescription" xml:space="preserve">
<value>Delete backward to the beginning of the previous word, as delimited by white space.</value>
</data>
<data name="ViDeleteGlobDescription" xml:space="preserve">
<value>Delete the current word, as delimited by white space.</value>
</data>
<data name="DeleteEndOfWordDescription" xml:space="preserve">
<value>Delete to the end of the current word, as delimited by white space and common delimiters.</value>
</data>
<data name="ViDeleteEndOfGlobDescription" xml:space="preserve">
<value>Delete to the end of this word, as delimited by white space.</value>
</data>
<data name="ViBackwardReplaceGlobDescription" xml:space="preserve">
<value>Delete backward to the beginning of the previous word, as delimited by white space, and enter insert mode.</value>
</data>
<data name="ViReplaceGlobDescription" xml:space="preserve">
<value>Delete to the beginning of the next word, as delimited by white space, and enter insert mode.</value>
</data>
<data name="ViReplaceEndOfWordDescription" xml:space="preserve">
<value>Delete to the end of the word, as delimited by white space and common delimiters, and enter insert mode.</value>
</data>
<data name="ViReplaceEndOfGlobDescription" xml:space="preserve">
<value>Delete to the end of the word, as delimited by white space, and enter insert mode.</value>
</data>
<data name="ViYankLineDescription" xml:space="preserve">
<value>Place all characters in the current line into the local clipboard.</value>
</data>
<data name="ViYankToEndOfLineDescription" xml:space="preserve">
<value>Place all characters at and after the cursor into the local clipboard.</value>
</data>
<data name="ViYankPreviousWordDescription" xml:space="preserve">
<value>Place all characters from before the cursor to the beginning of the previous word, as delimited by white space and common delimiters, into the local clipboard.</value>
</data>
<data name="ViYankPreviousGlobDescription" xml:space="preserve">
<value>Place all characters from before the cursor to the beginning of the previous word, as delimited by white space, into the local clipboard.</value>
</data>
<data name="ViYankNextWordDescription" xml:space="preserve">
<value>Place all characters from the cursor to the end of the word, as delimited by white space and common delimiters, into the local clipboard.</value>
</data>
<data name="ViYankNextGlobDescription" xml:space="preserve">
<value>Place all characters from the cursor to the end of the word, as delimited by white space, into the local clipboard.</value>
</data>
<data name="ViYankEndOfWordDescription" xml:space="preserve">
<value>Place the characters from the cursor to the end of the next word, as delimited by white space and common delimiters, into the local clipboard.</value>
</data>
<data name="ViYankEndOfGlobDescription" xml:space="preserve">
<value>Place the characters from the cursor to the end of the next white space delimited word into the local clipboard.</value>
</data>
<data name="ViYankLeftDescription" xml:space="preserve">
<value>Place the character to the left of the cursor into the local clipboard.</value>
</data>
<data name="ViYankRightDescription" xml:space="preserve">
<value>Place the character at the cursor into the local clipboard.</value>
</data>
<data name="ViYankBeginningOfLineDescription" xml:space="preserve">
<value>Place the characters before the cursor into the local clipboard.</value>
</data>
<data name="ViYankToFirstCharDescription" xml:space="preserve">
<value>Place all characters before the cursor and to the 1st non-white space character into the local clipboard.</value>
</data>
<data name="ViYankPercentDescription" xml:space="preserve">
<value>Place all characters between the matching brace and the cursor into the local clipboard.</value>
</data>
<data name="ViDeleteBraceDescription" xml:space="preserve">
<value>Deletes all characters between the cursor position and the matching brace.</value>
</data>
<data name="ViAcceptLineOrExitDescription" xml:space="preserve">
<value>If the line is empty, exit, otherwise accept the line as input.</value>
</data>
<data name="ViDigitArgumentInChordDescription" xml:space="preserve">
<value>Handles the processing of a number argument after the first key of a chord.</value>
</data>
<data name="ViExitDescription" xml:space="preserve">
<value>Exit the shell.</value>
</data>
<data name="ViTabCompleteNextDescription" xml:space="preserve">
<value>Invokes TabCompleteNext after doing some vi-specific clean up.</value>
</data>
<data name="ViTabCompletePreviousDescription" xml:space="preserve">
<value>Invokes TabCompletePrevious after doing some vi-specific clean up.</value>
</data>
<data name="ViEditVisuallyDescription" xml:space="preserve">
<value>Invokes the console compatible editor specified by $env:VISUAL or $env:$EDITOR on the current command line.</value>
</data>
<data name="ViAppendLineDescription" xml:space="preserve">
<value>Appends a new multi-line edit mode line to the current line.</value>
</data>
<data name="ViInsertLineDescription" xml:space="preserve">
<value>Inserts a new multi-line edit mode line in front of the current line.</value>
</data>
<data name="ViJoinLinesDescription" xml:space="preserve">
<value>Joins the current multi-line edit mode line with the next.</value>
</data>
<data name="NotInViMode" xml:space="preserve">
<value>The -ViMode parameter was used, but the current EditMode is not Vi.</value>
</data>
<data name="InsertLineAboveDescription" xml:space="preserve">
<value>Inserts a new empty line above the current line without attempting to execute the input</value>
</data>
<data name="InsertLineBelowDescription" xml:space="preserve">
<value>Inserts a new empty line below the current line without attempting to execute the input</value>
</data>
<data name="HistoryFileErrorMessage" xml:space="preserve">
<value>Error reading or writing history file '{0}': {1}</value>
</data>
<data name="HistoryFileErrorFinalMessage" xml:space="preserve">
<value>This error will not be reported again in this session. Consider using a different path with:
Set-PSReadlineOption -HistorySavePath &lt;Path&gt;
Or not saving history with:
Set-PSReadlineOption -HistorySaveStyle SaveNothing</value>
</data>
<data name="OopsCustomHandlerException" xml:space="preserve">
<value>An exception occurred in custom key handler, see $error for more information: {0}</value>
</data>
</root>

View file

@ -1,250 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Management.Automation;
using System.Management.Automation.Language;
using System.Management.Automation.Runspaces;
namespace Microsoft.PowerShell
{
namespace Internal
{
#pragma warning disable 1591
[SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")]
public interface IPSConsoleReadLineMockableMethods
{
void Ding();
CommandCompletion CompleteInput(string input, int cursorIndex, Hashtable options, System.Management.Automation.PowerShell powershell);
bool RunspaceIsRemote(Runspace runspace);
}
[SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")]
public interface IConsole
{
object GetConsoleInputMode();
void SetConsoleInputMode(object mode);
void RestoreConsoleInputMode(object mode);
ConsoleKeyInfo ReadKey();
bool KeyAvailable { get; }
int CursorLeft { get; set; }
int CursorTop { get; set;}
int CursorSize { get; set; }
int BufferWidth { get; set; }
int BufferHeight { get; set;}
int WindowWidth { get; set; }
int WindowHeight { get; set; }
int WindowTop { get; set; }
ConsoleColor BackgroundColor { get; set; }
ConsoleColor ForegroundColor { get; set; }
void SetWindowPosition(int left, int top);
void SetCursorPosition(int left, int top);
void WriteLine(string s);
void Write(string s);
void WriteBufferLines(BufferChar[] buffer, ref int top);
void WriteBufferLines(BufferChar[] buffer, ref int top, bool ensureBottomLineVisible);
void ScrollBuffer(int lines);
BufferChar[] ReadBufferLines(int top, int count);
void StartRender();
int LengthInBufferCells(char c);
void EndRender();
#if UNIX
void Clear();
#endif
}
#pragma warning restore 1591
}
/// <summary/>
public partial class PSConsoleReadLine
{
/// <summary>
/// Insert a character at the current position. Supports undo.
/// </summary>
/// <param name="c">Character to insert</param>
public static void Insert(char c)
{
_singleton.SaveEditItem(EditItemInsertChar.Create(c, _singleton._current));
// Use Append if possible because Insert at end makes StringBuilder quite slow.
if (_singleton._current == _singleton._buffer.Length)
{
_singleton._buffer.Append(c);
}
else
{
_singleton._buffer.Insert(_singleton._current, c);
}
_singleton._current += 1;
_singleton.Render();
}
/// <summary>
/// Insert a string at the current position. Supports undo.
/// </summary>
/// <param name="s">String to insert</param>
public static void Insert(string s)
{
_singleton.SaveEditItem(EditItemInsertString.Create(s, _singleton._current));
// Use Append if possible because Insert at end makes StringBuilder quite slow.
if (_singleton._current == _singleton._buffer.Length)
{
_singleton._buffer.Append(s);
}
else
{
_singleton._buffer.Insert(_singleton._current, s);
}
_singleton._current += s.Length;
_singleton.Render();
}
/// <summary>
/// Delete some text at the given position. Supports undo.
/// </summary>
/// <param name="start">The start position to delete</param>
/// <param name="length">The length to delete</param>
public static void Delete(int start, int length)
{
Replace(start, length, null);
}
/// <summary>
/// Replace some text at the given position. Supports undo.
/// </summary>
/// <param name="start">The start position to replace</param>
/// <param name="length">The length to replace</param>
/// <param name="replacement">The replacement text</param>
/// <param name="instigator">The action that initiated the replace (used for undo)</param>
/// <param name="instigatorArg">The argument to the action that initiated the replace (used for undo)</param>
public static void Replace(int start, int length, string replacement, Action<ConsoleKeyInfo?, object> instigator = null, object instigatorArg = null)
{
if (start < 0 || start > _singleton._buffer.Length)
{
throw new ArgumentException(PSReadLineResources.StartOutOfRange, "start");
}
if (length > (_singleton._buffer.Length - start))
{
throw new ArgumentException(PSReadLineResources.ReplacementLengthTooBig, "length");
}
bool useEditGroup = (_singleton._editGroupStart == -1);
if (useEditGroup)
{
_singleton.StartEditGroup();
}
var str = _singleton._buffer.ToString(start, length);
_singleton.SaveEditItem(EditItemDelete.Create(str, start));
_singleton._buffer.Remove(start, length);
if (replacement != null)
{
_singleton.SaveEditItem(EditItemInsertString.Create(replacement, start));
_singleton._buffer.Insert(start, replacement);
_singleton._current = start + replacement.Length;
}
else
{
_singleton._current = start;
}
if (useEditGroup)
{
_singleton.EndEditGroup(instigator, instigatorArg); // Instigator is needed for VI undo
_singleton.Render();
}
}
/// <summary>
/// Get the state of the buffer - the current input and the position of the cursor
/// </summary>
public static void GetBufferState(out string input, out int cursor)
{
input = _singleton._buffer.ToString();
cursor = _singleton._current;
}
/// <summary>
/// Get the state of the buffer - the ast, tokens, errors, and position of the cursor
/// </summary>
public static void GetBufferState(out Ast ast, out Token[] tokens, out ParseError[] parseErrors, out int cursor)
{
_singleton.ParseInput();
ast = _singleton._ast;
tokens = _singleton._tokens;
parseErrors = _singleton._parseErrors;
cursor = _singleton._current;
}
/// <summary>
/// Get the selection state of the buffer
/// </summary>
/// <param name="start">The start of the current selection or -1 if nothing is selected.</param>
/// <param name="length">The length of the current selection or -1 if nothing is selected.</param>
public static void GetSelectionState(out int start, out int length)
{
if (_singleton._visualSelectionCommandCount == 0)
{
start = -1;
length = -1;
}
else
{
_singleton.GetRegion(out start, out length);
}
}
/// <summary>
/// Set the position of the cursor.
/// </summary>
public static void SetCursorPosition(int cursor)
{
if (cursor > _singleton._buffer.Length + ViEndOfLineFactor)
{
cursor = _singleton._buffer.Length + ViEndOfLineFactor;
}
if (cursor < 0)
{
cursor = 0;
}
_singleton._current = cursor;
_singleton.PlaceCursor();
}
/// <summary>
/// A helper method when your function expects an optional int argument (e.g. from DigitArgument)
/// If there is not argument (it's null), returns true and sets numericArg to defaultNumericArg.
/// Dings and returns false if the argument is not an int (no conversion is attempted)
/// Otherwise returns true, and numericArg has the result.
/// </summary>
public static bool TryGetArgAsInt(object arg, out int numericArg, int defaultNumericArg)
{
if (arg == null)
{
numericArg = defaultNumericArg;
return true;
}
if (arg is int)
{
numericArg = (int)arg;
return true;
}
Ding();
numericArg = 0;
return false;
}
}
}

View file

@ -1,957 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Language;
using System.Management.Automation.Runspaces;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Microsoft.PowerShell.Commands;
using Microsoft.PowerShell.Internal;
[module: SuppressMessage("Microsoft.Design", "CA1014:MarkAssembliesWithClsCompliant")]
namespace Microsoft.PowerShell
{
[SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors")]
[SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")]
class ExitException : Exception { }
public partial class PSConsoleReadLine : IPSConsoleReadLineMockableMethods
{
private static readonly PSConsoleReadLine _singleton = new PSConsoleReadLine();
private bool _delayedOneTimeInitCompleted;
private IPSConsoleReadLineMockableMethods _mockableMethods;
private IConsole _console;
private EngineIntrinsics _engineIntrinsics;
#if !UNIX
private static GCHandle _breakHandlerGcHandle;
#endif
private Thread _readKeyThread;
private AutoResetEvent _readKeyWaitHandle;
private AutoResetEvent _keyReadWaitHandle;
private ManualResetEvent _closingWaitHandle;
private WaitHandle[] _threadProcWaitHandles;
private WaitHandle[] _requestKeyWaitHandles;
private object _savedConsoleInputMode;
private readonly StringBuilder _buffer;
private readonly StringBuilder _statusBuffer;
private bool _statusIsErrorMessage;
private string _statusLinePrompt;
private List<EditItem> _edits;
private int _editGroupStart;
private int _undoEditIndex;
private int _mark;
private bool _inputAccepted;
private readonly Queue<ConsoleKeyInfo> _queuedKeys;
private Stopwatch _lastRenderTime;
private static Stopwatch _readkeyStopwatch = new Stopwatch();
// Save a fixed # of keys so we can reconstruct a repro after a crash
private readonly static HistoryQueue<ConsoleKeyInfo> _lastNKeys = new HistoryQueue<ConsoleKeyInfo>(200);
// Tokens etc.
private Token[] _tokens;
private Ast _ast;
private ParseError[] _parseErrors;
bool IPSConsoleReadLineMockableMethods.RunspaceIsRemote(Runspace runspace)
{
return runspace != null && runspace.ConnectionInfo != null;
}
private void ReadOneOrMoreKeys()
{
_readkeyStopwatch.Restart();
while (_console.KeyAvailable)
{
var key = _console.ReadKey();
_lastNKeys.Enqueue(key);
_queuedKeys.Enqueue(key);
if (_readkeyStopwatch.ElapsedMilliseconds > 2)
{
// Don't spend too long in this loop if there are lots of queued keys
break;
}
}
if (_queuedKeys.Count == 0)
{
var key = _console.ReadKey();
_lastNKeys.Enqueue(key);
_queuedKeys.Enqueue(key);
}
}
private void ReadKeyThreadProc()
{
while (true)
{
// Wait until ReadKey tells us to read a key (or it's time to exit).
int handleId = WaitHandle.WaitAny(_singleton._threadProcWaitHandles);
if (handleId == 1) // It was the _closingWaitHandle that was signaled.
break;
ReadOneOrMoreKeys();
// One or more keys were read - let ReadKey know we're done.
_keyReadWaitHandle.Set();
}
}
private static ConsoleKeyInfo ReadKey()
{
// Reading a key is handled on a different thread. During process shutdown,
// PowerShell will wait in it's ConsoleCtrlHandler until the pipeline has completed.
// If we're running, we're most likely blocked waiting for user input.
// This is a problem for two reasons. First, exiting takes a long time (5 seconds
// on Win8) because PowerShell is waiting forever, but the OS will forcibly terminate
// the console. Also - if there are any event handlers for the engine event
// PowerShell.Exiting, those handlers won't get a chance to run.
//
// By waiting for a key on a different thread, our pipeline execution thread
// (the thread Readline is called from) avoid being blocked in code that can't
// be unblocked and instead blocks on events we control.
// First, set an event so the thread to read a key actually attempts to read a key.
_singleton._readKeyWaitHandle.Set();
int handleId;
System.Management.Automation.PowerShell ps = null;
try
{
while (true)
{
// Next, wait for one of three things:
// - a key is pressed
// - the console is exiting
// - 300ms - to process events if we're idle
handleId = WaitHandle.WaitAny(_singleton._requestKeyWaitHandles, 300);
if (handleId != WaitHandle.WaitTimeout)
break;
if (_singleton._engineIntrinsics == null)
continue;
// If we timed out, check for event subscribers (which is just
// a hint that there might be an event waiting to be processed.)
var eventSubscribers = _singleton._engineIntrinsics.Events.Subscribers;
if (eventSubscribers.Count > 0)
{
bool runPipelineForEventProcessing = false;
foreach (var sub in eventSubscribers)
{
if (sub.SourceIdentifier.Equals("PowerShell.OnIdle", StringComparison.OrdinalIgnoreCase))
{
// There is an OnIdle event. We're idle because we timed out. Normally
// PowerShell generates this event, but PowerShell assumes the engine is not
// idle because it called PSConsoleHostReadline which isn't returning.
// So we generate the event instead.
_singleton._engineIntrinsics.Events.GenerateEvent("PowerShell.OnIdle", null, null, null);
runPipelineForEventProcessing = true;
break;
}
// If there are any event subscribers that have an action (which might
// write to the console) and have a source object (i.e. aren't engine
// events), run a tiny useless bit of PowerShell so that the events
// can be processed.
if (sub.Action != null && sub.SourceObject != null)
{
runPipelineForEventProcessing = true;
break;
}
}
if (runPipelineForEventProcessing)
{
if (ps == null)
{
ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace);
ps.AddScript("0");
}
// To detect output during possible event processing, see if the cursor moved
// and rerender if so.
var console = _singleton._console;
var y = console.CursorTop;
ps.Invoke();
if (y != console.CursorTop)
{
_singleton._initialY = console.CursorTop;
_singleton.Render();
}
}
}
}
}
finally
{
if (ps != null) { ps.Dispose(); }
}
if (handleId == 1)
{
// The console is exiting - throw an exception to unwind the stack to the point
// where we can return from ReadLine.
if (_singleton.Options.HistorySaveStyle == HistorySaveStyle.SaveAtExit)
{
_singleton.SaveHistoryAtExit();
}
_singleton._historyFileMutex.Dispose();
throw new OperationCanceledException();
}
var key = _singleton._queuedKeys.Dequeue();
return key;
}
private void PrependQueuedKeys(ConsoleKeyInfo key)
{
if (_queuedKeys.Count > 0)
{
// This should almost never happen so being inefficient is fine.
var list = new List<ConsoleKeyInfo>(_queuedKeys);
_queuedKeys.Clear();
_queuedKeys.Enqueue(key);
list.ForEach(k => _queuedKeys.Enqueue(k));
}
else
{
_queuedKeys.Enqueue(key);
}
}
private bool BreakHandler(ConsoleBreakSignal signal)
{
if (signal == ConsoleBreakSignal.Close || signal == ConsoleBreakSignal.Shutdown)
{
// Set the event so ReadKey throws an exception to unwind.
_closingWaitHandle.Set();
}
return false;
}
/// <summary>
/// Entry point - called from the PowerShell function PSConsoleHostReadline
/// after the prompt has been displayed.
/// </summary>
/// <returns>The complete command line.</returns>
public static string ReadLine(Runspace runspace, EngineIntrinsics engineIntrinsics)
{
var console = _singleton._console;
// 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 (Console.IsInputRedirected || Console.IsOutputRedirected)
{
throw new NotSupportedException();
}
_singleton._savedConsoleInputMode = _singleton._console.GetConsoleInputMode();
bool firstTime = true;
while (true)
{
try
{
_singleton._console.SetConsoleInputMode(_singleton._savedConsoleInputMode);
if (firstTime)
{
firstTime = false;
_singleton.Initialize(runspace, engineIntrinsics);
}
return _singleton.InputLoop();
}
catch (OperationCanceledException)
{
// Console is exiting - return value isn't too critical - null or 'exit' could work equally well.
return "";
}
catch (ExitException)
{
return "exit";
}
catch (CustomHandlerException e)
{
var oldColor = console.ForegroundColor;
console.ForegroundColor = ConsoleColor.Red;
console.WriteLine(
string.Format(CultureInfo.CurrentUICulture, PSReadLineResources.OopsCustomHandlerException, e.InnerException.Message));
console.ForegroundColor = oldColor;
var lineBeforeCrash = _singleton._buffer.ToString();
_singleton.Initialize(runspace, _singleton._engineIntrinsics);
InvokePrompt();
Insert(lineBeforeCrash);
}
catch (Exception e)
{
// If we're running tests, just throw.
if (_singleton._mockableMethods != _singleton)
{
throw;
}
while (e.InnerException != null)
{
e = e.InnerException;
}
var oldColor = console.ForegroundColor;
console.ForegroundColor = ConsoleColor.Red;
console.WriteLine(PSReadLineResources.OopsAnErrorMessage1);
console.ForegroundColor = oldColor;
var sb = new StringBuilder();
for (int i = 0; i < _lastNKeys.Count; i++)
{
sb.Append(' ');
sb.Append(_lastNKeys[i].ToGestureString());
KeyHandler handler;
if (_singleton._dispatchTable.TryGetValue(_lastNKeys[i], out handler) &&
"AcceptLine".Equals(handler.BriefDescription, StringComparison.OrdinalIgnoreCase))
{
// Make it a little easier to see the keys
sb.Append('\n');
}
}
console.WriteLine(string.Format(CultureInfo.CurrentUICulture, PSReadLineResources.OopsAnErrorMessage2, _lastNKeys.Count, sb, e));
var lineBeforeCrash = _singleton._buffer.ToString();
_singleton.Initialize(runspace, _singleton._engineIntrinsics);
InvokePrompt();
Insert(lineBeforeCrash);
}
finally
{
_singleton._console.RestoreConsoleInputMode(_singleton._savedConsoleInputMode);
}
}
}
private string InputLoop()
{
ProcessViVisualEditing();
while (true)
{
var killCommandCount = _killCommandCount;
var yankCommandCount = _yankCommandCount;
var tabCommandCount = _tabCommandCount;
var searchHistoryCommandCount = _searchHistoryCommandCount;
var recallHistoryCommandCount = _recallHistoryCommandCount;
var yankLastArgCommandCount = _yankLastArgCommandCount;
var visualSelectionCommandCount = _visualSelectionCommandCount;
var movingAtEndOfLineCount = _moveToLineCommandCount;
var key = ReadKey();
ProcessOneKey(key, _dispatchTable, ignoreIfNoAction: false, arg: null);
if (_inputAccepted)
{
return MaybeAddToHistory(_buffer.ToString(), _edits, _undoEditIndex, readingHistoryFile: false, fromDifferentSession: false);
}
if (killCommandCount == _killCommandCount)
{
// Reset kill command count if it didn't change
_killCommandCount = 0;
}
if (yankCommandCount == _yankCommandCount)
{
// Reset yank command count if it didn't change
_yankCommandCount = 0;
}
if (yankLastArgCommandCount == _yankLastArgCommandCount)
{
// Reset yank last arg command count if it didn't change
_yankLastArgCommandCount = 0;
_yankLastArgState = null;
}
if (tabCommandCount == _tabCommandCount)
{
// Reset tab command count if it didn't change
_tabCommandCount = 0;
_tabCompletions = null;
}
if (searchHistoryCommandCount == _searchHistoryCommandCount)
{
if (_searchHistoryCommandCount > 0)
{
_emphasisStart = -1;
_emphasisLength = 0;
Render();
_currentHistoryIndex = _history.Count;
}
_searchHistoryCommandCount = 0;
_searchHistoryPrefix = null;
}
if (recallHistoryCommandCount == _recallHistoryCommandCount)
{
if (_recallHistoryCommandCount > 0)
{
_currentHistoryIndex = _history.Count;
}
_recallHistoryCommandCount = 0;
}
if (searchHistoryCommandCount == _searchHistoryCommandCount &&
recallHistoryCommandCount == _recallHistoryCommandCount)
{
_hashedHistory = null;
}
if (visualSelectionCommandCount == _visualSelectionCommandCount && _visualSelectionCommandCount > 0)
{
_visualSelectionCommandCount = 0;
Render(); // Clears the visual selection
}
if (movingAtEndOfLineCount == _moveToLineCommandCount)
{
_moveToLineCommandCount = 0;
}
}
}
T CalloutUsingDefaultConsoleMode<T>(Func<T> func)
{
var currentMode = _console.GetConsoleInputMode();
try
{
_console.RestoreConsoleInputMode(_savedConsoleInputMode);
return func();
}
finally
{
_console.RestoreConsoleInputMode(currentMode);
}
}
void CalloutUsingDefaultConsoleMode(Action action)
{
CalloutUsingDefaultConsoleMode<object>(() => { action(); return null; });
}
void ProcessOneKey(ConsoleKeyInfo key, Dictionary<ConsoleKeyInfo, KeyHandler> dispatchTable, bool ignoreIfNoAction, object arg)
{
KeyHandler handler;
if (!dispatchTable.TryGetValue(key, out handler))
{
// If we see a control character where Ctrl wasn't used but shift was, treat that like
// shift hadn't be pressed. This cleanly allows Shift+Backspace without adding a key binding.
if (key.KeyChar > 0 && char.IsControl(key.KeyChar) && key.Modifiers == ConsoleModifiers.Shift)
{
key = new ConsoleKeyInfo(key.KeyChar, key.Key, false, false, false);
dispatchTable.TryGetValue(key, out handler);
}
}
if (handler != null)
{
if (handler.ScriptBlock != null)
{
CalloutUsingDefaultConsoleMode(() => handler.Action(key, arg));
}
else
{
handler.Action(key, arg);
}
}
else if (!ignoreIfNoAction && key.KeyChar != 0)
{
SelfInsert(key, arg);
}
}
private PSConsoleReadLine()
{
_mockableMethods = this;
#if UNIX
_console = new TTYConsole();
#else
_console = new ConhostConsole();
#endif
_buffer = new StringBuilder(8 * 1024);
_statusBuffer = new StringBuilder(256);
_savedCurrentLine = new HistoryItem();
_queuedKeys = new Queue<ConsoleKeyInfo>();
string hostName = null;
// This works mostly by luck - we're not doing anything to guarantee the constructor for our
// singleton is called on a thread with a runspace, but it is happening by coincidence.
using (var ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace))
{
try
{
ps.AddCommand("Get-Variable").AddParameter("Name", "host").AddParameter("ValueOnly");
var results = ps.Invoke();
dynamic host = results.Count == 1 ? results[0] : null;
if (host != null)
{
hostName = host.Name as string;
}
}
catch
{
}
}
if (hostName == null)
{
hostName = "PSReadline";
}
_options = new PSConsoleReadlineOptions(hostName);
SetDefaultBindings(_options.EditMode);
}
private void Initialize(Runspace runspace, EngineIntrinsics engineIntrinsics)
{
_engineIntrinsics = engineIntrinsics;
_runspace = runspace;
if (!_delayedOneTimeInitCompleted)
{
DelayedOneTimeInitialize();
_delayedOneTimeInitCompleted = true;
}
_buffer.Clear();
_edits = new List<EditItem>();
_undoEditIndex = 0;
_editGroupStart = -1;
_current = 0;
_mark = 0;
_emphasisStart = -1;
_emphasisLength = 0;
_tokens = null;
_parseErrors = null;
_inputAccepted = false;
_initialX = _console.CursorLeft;
_initialY = _console.CursorTop - Options.ExtraPromptLineCount;
_initialBackgroundColor = _console.BackgroundColor;
_initialForegroundColor = _console.ForegroundColor;
_space = new BufferChar
{
UnicodeChar = ' ',
BackgroundColor = _initialBackgroundColor,
ForegroundColor = _initialForegroundColor
};
_bufferWidth = _console.BufferWidth;
_killCommandCount = 0;
_yankCommandCount = 0;
_yankLastArgCommandCount = 0;
_tabCommandCount = 0;
_visualSelectionCommandCount = 0;
_statusIsErrorMessage = false;
#if UNIX // TODO: not necessary if ReadBufferLines worked, or if rendering worked on spans instead of complete lines
string newPrompt = GetPrompt();
int index = newPrompt.LastIndexOf('\n');
if (index != -1)
{
// The prompt text could be a multi-line string, and in such case
// we only want the part of it that is shown on the input line.
newPrompt = newPrompt.Substring(index + 1);
}
var bufferLineCount = (newPrompt.Length) / (_console.BufferWidth) + 1;
_consoleBuffer = ReadBufferLines(_initialY, bufferLineCount);
for (int i=0; i<newPrompt.Length; ++i)
{
_consoleBuffer[i].UnicodeChar = newPrompt[i];
}
#else
_consoleBuffer = ReadBufferLines(_initialY, 1 + Options.ExtraPromptLineCount);
#endif
_lastRenderTime = Stopwatch.StartNew();
_killCommandCount = 0;
_yankCommandCount = 0;
_yankLastArgCommandCount = 0;
_tabCommandCount = 0;
_recallHistoryCommandCount = 0;
_visualSelectionCommandCount = 0;
_hashedHistory = null;
if (_getNextHistoryIndex > 0)
{
_currentHistoryIndex = _getNextHistoryIndex;
UpdateFromHistory(moveCursor: true);
_getNextHistoryIndex = 0;
if (_searchHistoryCommandCount > 0)
{
_searchHistoryPrefix = "";
if (Options.HistoryNoDuplicates)
{
_hashedHistory = new Dictionary<string, int>();
}
}
}
else
{
_searchHistoryCommandCount = 0;
}
}
private void DelayedOneTimeInitialize()
{
// Delayed initialization is needed so that options can be set
// after the constuctor but have an affect before the user starts
// editing their first command line. For example, if the user
// specifies a custom history save file, we don't want to try reading
// from the default one.
if (_engineIntrinsics != null)
{
var historyCountVar = _engineIntrinsics.SessionState.PSVariable.Get("MaximumHistoryCount");
if (historyCountVar != null && historyCountVar.Value is int)
{
_options.MaximumHistoryCount = (int)historyCountVar.Value;
}
}
#if UNIX
_historyFileMutex = new Mutex(false);
#else
_historyFileMutex = new Mutex(false, GetHistorySaveFileMutexName());
#endif
_history = new HistoryQueue<HistoryItem>(Options.MaximumHistoryCount);
_currentHistoryIndex = 0;
bool readHistoryFile = true;
try
{
if (_options.HistorySaveStyle == HistorySaveStyle.SaveNothing && Runspace.DefaultRunspace != null)
{
using (var ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace))
{
ps.AddCommand("Microsoft.PowerShell.Core\\Get-History");
foreach (var historyInfo in ps.Invoke<HistoryInfo>())
{
AddToHistory(historyInfo.CommandLine);
}
readHistoryFile = false;
}
}
}
catch
{
}
if (readHistoryFile)
{
ReadHistoryFile();
}
_killIndex = -1; // So first add indexes 0.
_killRing = new List<string>(Options.MaximumKillRingCount);
#if !UNIX
_breakHandlerGcHandle = GCHandle.Alloc(new BreakHandler(_singleton.BreakHandler));
NativeMethods.SetConsoleCtrlHandler((BreakHandler)_breakHandlerGcHandle.Target, true);
#endif
_singleton._readKeyWaitHandle = new AutoResetEvent(false);
_singleton._keyReadWaitHandle = new AutoResetEvent(false);
_singleton._closingWaitHandle = new ManualResetEvent(false);
_singleton._requestKeyWaitHandles = new WaitHandle[] {_singleton._keyReadWaitHandle, _singleton._closingWaitHandle};
_singleton._threadProcWaitHandles = new WaitHandle[] {_singleton._readKeyWaitHandle, _singleton._closingWaitHandle};
#if !CORECLR
// This is for a "being hosted in an alternate appdomain scenario" (the
// DomainUnload event is not raised for the default appdomain). It allows us
// to exit cleanly when the appdomain is unloaded but the process is not going
// away.
if (!AppDomain.CurrentDomain.IsDefaultAppDomain())
{
AppDomain.CurrentDomain.DomainUnload += (x, y) =>
{
_singleton._closingWaitHandle.Set();
_singleton._readKeyThread.Join(); // may need to wait for history to be written
};
}
#endif
_singleton._readKeyThread = new Thread(_singleton.ReadKeyThreadProc) {IsBackground = true};
_singleton._readKeyThread.Start();
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
private static void Chord(ConsoleKeyInfo? key = null, object arg = null)
{
if (!key.HasValue)
{
throw new ArgumentNullException("key");
}
Dictionary<ConsoleKeyInfo, KeyHandler> secondKeyDispatchTable;
if (_singleton._chordDispatchTable.TryGetValue(key.Value, out secondKeyDispatchTable))
{
var secondKey = ReadKey();
_singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: arg);
}
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
private static void Ignore(ConsoleKeyInfo? key = null, object arg = null)
{
}
private static void ExecuteOnSTAThread(Action action)
{
#if CORECLR
action();
#else
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
{
action();
return;
}
Exception exception = null;
var thread = new Thread(() =>
{
try
{
action();
}
catch (Exception e)
{
exception = e;
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
if (exception != null)
{
throw exception;
}
#endif
}
#region Miscellaneous bindable functions
/// <summary>
/// Abort current action, e.g. incremental history search
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void Abort(ConsoleKeyInfo? key = null, object arg = null)
{
}
/// <summary>
/// Start a new digit argument to pass to other functions
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void DigitArgument(ConsoleKeyInfo? key = null, object arg = null)
{
if (!key.HasValue || char.IsControl(key.Value.KeyChar))
{
Ding();
return;
}
if (_singleton._options.EditMode == EditMode.Vi && key.Value.KeyChar == '0')
{
BeginningOfLine();
return;
}
bool sawDigit = false;
_singleton._statusLinePrompt = "digit-argument: ";
var argBuffer = _singleton._statusBuffer;
argBuffer.Append(key.Value.KeyChar);
if (key.Value.KeyChar == '-')
{
argBuffer.Append('1');
}
else
{
sawDigit = true;
}
_singleton.Render(); // Render prompt
while (true)
{
var nextKey = ReadKey();
KeyHandler handler;
if (_singleton._dispatchTable.TryGetValue(nextKey, out handler))
{
if (handler.Action == DigitArgument)
{
if (nextKey.KeyChar == '-')
{
if (argBuffer[0] == '-')
{
argBuffer.Remove(0, 1);
}
else
{
argBuffer.Insert(0, '-');
}
_singleton.Render(); // Render prompt
continue;
}
if (nextKey.KeyChar >= '0' && nextKey.KeyChar <= '9')
{
if (!sawDigit && argBuffer.Length > 0)
{
// Buffer is either '-1' or '1' from one or more Alt+- keys
// but no digits yet. Remove the '1'.
argBuffer.Length -= 1;
}
sawDigit = true;
argBuffer.Append(nextKey.KeyChar);
_singleton.Render(); // Render prompt
continue;
}
}
else if (handler.Action == Abort ||
handler.Action == CancelLine ||
handler.Action == CopyOrCancelLine)
{
break;
}
}
int intArg;
if (int.TryParse(argBuffer.ToString(), out intArg))
{
_singleton.ProcessOneKey(nextKey, _singleton._dispatchTable, ignoreIfNoAction: false, arg: intArg);
}
else
{
Ding();
}
break;
}
// Remove our status line
argBuffer.Clear();
_singleton.ClearStatusMessage(render: true);
}
/// <summary>
/// Erases the current prompt and calls the prompt function to redisplay
/// the prompt. Useful for custom key handlers that change state, e.g.
/// change the current directory.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void InvokePrompt(ConsoleKeyInfo? key = null, object arg = null)
{
var currentBuffer = _singleton._buffer.ToString();
var currentPos = _singleton._current;
_singleton._buffer.Clear();
_singleton._current = 0;
for (int i = 0; i < _singleton._consoleBuffer.Length; i++)
{
_singleton._consoleBuffer[i].UnicodeChar = ' ';
_singleton._consoleBuffer[i].ForegroundColor = _singleton._console.ForegroundColor;
_singleton._consoleBuffer[i].BackgroundColor = _singleton._console.BackgroundColor;
}
_singleton.Render();
_singleton._console.CursorLeft = 0;
_singleton._console.CursorTop = _singleton._initialY - _singleton.Options.ExtraPromptLineCount;
string newPrompt = GetPrompt();
_singleton._console.Write(newPrompt);
_singleton._initialX = _singleton._console.CursorLeft;
_singleton._consoleBuffer = ReadBufferLines(_singleton._initialY, 1 + _singleton.Options.ExtraPromptLineCount);
#if UNIX // TODO: ReadBufferLines only needed for extra line, but doesn't work on Linux
for (int i=0; i<newPrompt.Length; ++i)
{
_singleton._consoleBuffer[i].UnicodeChar = newPrompt[i];
}
#endif
_singleton._buffer.Append(currentBuffer);
_singleton._current = currentPos;
_singleton.Render();
}
private const string PromptCommand = "prompt";
private const string DefaultPrompt = "PS>";
/// <summary>
/// Gets the current prompt as possibly defined by the user through the
/// prompt function, and returns a default prompt if no other is
/// available. Also handles remote prompts.
/// </summary>
public static string GetPrompt()
{
string newPrompt;
var runspaceIsRemote = _singleton._mockableMethods.RunspaceIsRemote(_singleton._runspace);
if ((_singleton._runspace.Debugger != null) && _singleton._runspace.Debugger.InBreakpoint)
{
// Run prompt command in debugger API to ensure it is run correctly on the runspace.
// This handles remote runspace debugging and nested debugger scenarios.
PSDataCollection<PSObject> results = new PSDataCollection<PSObject>();
var command = new PSCommand();
command.AddCommand(PromptCommand);
_singleton._runspace.Debugger.ProcessCommand(
command,
results);
newPrompt = (results.Count == 1) ? (results[0].BaseObject as string) : DefaultPrompt;
}
else
{
System.Management.Automation.PowerShell ps;
if (!runspaceIsRemote)
{
ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace);
}
else
{
ps = System.Management.Automation.PowerShell.Create();
ps.Runspace = _singleton._runspace;
}
using (ps)
{
ps.AddCommand(PromptCommand);
var result = ps.Invoke<string>();
newPrompt = result.Count == 1 ? result[0] : DefaultPrompt;
}
}
if (string.IsNullOrEmpty(newPrompt))
{
newPrompt = DefaultPrompt;
}
if (runspaceIsRemote)
{
var connectionInfo = _singleton._runspace.ConnectionInfo;
if (!string.IsNullOrEmpty(connectionInfo.ComputerName))
{
newPrompt = string.Format(CultureInfo.InvariantCulture, "[{0}]: {1}", connectionInfo.ComputerName, newPrompt);
}
}
return newPrompt;
}
#endregion Miscellaneous bindable functions
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,815 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Management.Automation.Language;
using Microsoft.PowerShell.Internal;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
#if UNIX
private const ConsoleColor UnknownColor = (ConsoleColor) (-1);
#endif
private BufferChar[] _consoleBuffer;
private int _initialX;
private int _initialY;
private int _bufferWidth;
private ConsoleColor _initialBackgroundColor;
private ConsoleColor _initialForegroundColor;
private BufferChar _space;
private int _current;
private int _emphasisStart;
private int _emphasisLength;
private class SavedTokenState
{
internal Token[] Tokens { get; set; }
internal int Index { get; set; }
internal ConsoleColor BackgroundColor { get; set; }
internal ConsoleColor ForegroundColor { get; set; }
}
private void MaybeParseInput()
{
if (_tokens == null)
{
ParseInput();
}
}
private string ParseInput()
{
var text = _buffer.ToString();
_ast = Parser.ParseInput(text, out _tokens, out _parseErrors);
return text;
}
private void ClearStatusMessage(bool render)
{
_statusBuffer.Clear();
_statusLinePrompt = null;
_statusIsErrorMessage = false;
if (render)
{
Render();
}
}
private void Render()
{
// If there are a bunch of keys queued up, skip rendering if we've rendered
// recently.
if (_queuedKeys.Count > 10 && (_lastRenderTime.ElapsedMilliseconds < 50))
{
// We won't render, but most likely the tokens will be different, so make
// sure we don't use old tokens.
_tokens = null;
_ast = null;
return;
}
ReallyRender();
}
[SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults")]
private void ReallyRender()
{
var text = ParseInput();
int statusLineCount = GetStatusLineCount();
int j = _initialX + (_bufferWidth * Options.ExtraPromptLineCount);
var backgroundColor = _initialBackgroundColor;
var foregroundColor = _initialForegroundColor;
bool afterLastToken = false;
int totalBytes = j;
int bufferWidth = _console.BufferWidth;
var tokenStack = new Stack<SavedTokenState>();
tokenStack.Push(new SavedTokenState
{
Tokens = _tokens,
Index = 0,
BackgroundColor = _initialBackgroundColor,
ForegroundColor = _initialForegroundColor
});
int bufferLineCount;
try
{
_console.StartRender();
bufferLineCount = ConvertOffsetToCoordinates(text.Length).Y - _initialY + 1 + statusLineCount;
if (_consoleBuffer.Length != bufferLineCount * bufferWidth)
{
var newBuffer = new BufferChar[bufferLineCount * bufferWidth];
Array.Copy(_consoleBuffer, newBuffer, _initialX + (Options.ExtraPromptLineCount * _bufferWidth));
if (_consoleBuffer.Length > bufferLineCount * bufferWidth)
{
int consoleBufferOffset = ConvertOffsetToConsoleBufferOffset(text.Length, _initialX + (Options.ExtraPromptLineCount * _bufferWidth));
// Need to erase the extra lines that we won't draw again
for (int i = consoleBufferOffset; i < _consoleBuffer.Length; i++)
{
_consoleBuffer[i] = _space;
}
_console.WriteBufferLines(_consoleBuffer, ref _initialY);
}
_consoleBuffer = newBuffer;
}
for (int i = 0; i < text.Length; i++)
{
totalBytes = totalBytes % bufferWidth;
if (!afterLastToken)
{
// Figure out the color of the character - if it's in a token,
// use the tokens color otherwise use the initial color.
var state = tokenStack.Peek();
var token = state.Tokens[state.Index];
if (i == token.Extent.EndOffset)
{
if (token == state.Tokens[state.Tokens.Length - 1])
{
tokenStack.Pop();
if (tokenStack.Count == 0)
{
afterLastToken = true;
token = null;
foregroundColor = _initialForegroundColor;
backgroundColor = _initialBackgroundColor;
}
else
{
state = tokenStack.Peek();
}
}
if (!afterLastToken)
{
foregroundColor = state.ForegroundColor;
backgroundColor = state.BackgroundColor;
token = state.Tokens[++state.Index];
}
}
if (!afterLastToken && i == token.Extent.StartOffset)
{
GetTokenColors(token, out foregroundColor, out backgroundColor);
var stringToken = token as StringExpandableToken;
if (stringToken != null)
{
// We might have nested tokens.
if (stringToken.NestedTokens != null && stringToken.NestedTokens.Any())
{
var tokens = new Token[stringToken.NestedTokens.Count + 1];
stringToken.NestedTokens.CopyTo(tokens, 0);
// NestedTokens doesn't have an "EOS" token, so we use
// the string literal token for that purpose.
tokens[tokens.Length - 1] = stringToken;
tokenStack.Push(new SavedTokenState
{
Tokens = tokens,
Index = 0,
BackgroundColor = backgroundColor,
ForegroundColor = foregroundColor
});
if (i == tokens[0].Extent.StartOffset)
{
GetTokenColors(tokens[0], out foregroundColor, out backgroundColor);
}
}
}
}
}
var charToRender = text[i];
if (charToRender == '\n')
{
while ((j % bufferWidth) != 0)
{
_consoleBuffer[j++] = _space;
}
for (int k = 0; k < Options.ContinuationPrompt.Length; k++, j++)
{
_consoleBuffer[j].UnicodeChar = Options.ContinuationPrompt[k];
_consoleBuffer[j].ForegroundColor = Options.ContinuationPromptForegroundColor;
_consoleBuffer[j].BackgroundColor = Options.ContinuationPromptBackgroundColor;
}
}
else
{
int size = LengthInBufferCells(charToRender);
totalBytes += size;
//if there is no enough space for the character at the edge, fill in spaces at the end and
//put the character to next line.
int filling = totalBytes > bufferWidth ? (totalBytes - bufferWidth) % size : 0;
for (int f = 0; f < filling; f++)
{
_consoleBuffer[j++] = _space;
totalBytes++;
}
if (char.IsControl(charToRender))
{
_consoleBuffer[j].UnicodeChar = '^';
MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
_consoleBuffer[j].UnicodeChar = (char)('@' + charToRender);
MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
}
#if !UNIX
else if (size > 1)
{
_consoleBuffer[j].UnicodeChar = charToRender;
_consoleBuffer[j].IsLeadByte = true;
MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
_consoleBuffer[j].UnicodeChar = charToRender;
_consoleBuffer[j].IsTrailByte = true;
MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
}
#endif
else
{
_consoleBuffer[j].UnicodeChar = charToRender;
MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
}
}
}
}
finally
{
_console.EndRender();
}
for (; j < (_consoleBuffer.Length - (statusLineCount * _bufferWidth)); j++)
{
_consoleBuffer[j] = _space;
}
if (_statusLinePrompt != null)
{
foregroundColor = _statusIsErrorMessage ? Options.ErrorForegroundColor : _console.ForegroundColor;
backgroundColor = _statusIsErrorMessage ? Options.ErrorBackgroundColor : _console.BackgroundColor;
for (int i = 0; i < _statusLinePrompt.Length; i++, j++)
{
_consoleBuffer[j].UnicodeChar = _statusLinePrompt[i];
_consoleBuffer[j].ForegroundColor = foregroundColor;
_consoleBuffer[j].BackgroundColor = backgroundColor;
}
for (int i = 0; i < _statusBuffer.Length; i++, j++)
{
_consoleBuffer[j].UnicodeChar = _statusBuffer[i];
_consoleBuffer[j].ForegroundColor = foregroundColor;
_consoleBuffer[j].BackgroundColor = backgroundColor;
}
for (; j < _consoleBuffer.Length; j++)
{
_consoleBuffer[j] = _space;
}
}
bool rendered = false;
if (_parseErrors.Length > 0)
{
int promptChar = _initialX - 1 + (_bufferWidth * Options.ExtraPromptLineCount);
while (promptChar >= 0)
{
var c = _consoleBuffer[promptChar].UnicodeChar;
if (char.IsWhiteSpace(c))
{
promptChar -= 1;
continue;
}
ConsoleColor prevColor = _consoleBuffer[promptChar].ForegroundColor;
_consoleBuffer[promptChar].ForegroundColor = ConsoleColor.Red;
_console.WriteBufferLines(_consoleBuffer, ref _initialY);
rendered = true;
_consoleBuffer[promptChar].ForegroundColor = prevColor;
break;
}
}
if (!rendered)
{
_console.WriteBufferLines(_consoleBuffer, ref _initialY);
}
PlaceCursor();
if ((_initialY + bufferLineCount) > (_console.WindowTop + _console.WindowHeight))
{
#if !UNIX // TODO: verify this isn't necessary for LINUX
_console.WindowTop = _initialY + bufferLineCount - _console.WindowHeight;
#endif
}
_lastRenderTime.Restart();
}
private int LengthInBufferCells(char c)
{
int length = Char.IsControl(c) ? 1 : 0;
if (c < 256)
{
return length + 1;
}
return _console.LengthInBufferCells(c);
}
private static void WriteBlankLines(int count, int top)
{
var console = _singleton._console;
var blanks = new BufferChar[count * console.BufferWidth];
for (int i = 0; i < blanks.Length; i++)
{
blanks[i].BackgroundColor = console.BackgroundColor;
blanks[i].ForegroundColor = console.ForegroundColor;
blanks[i].UnicodeChar = ' ';
}
console.WriteBufferLines(blanks, ref top);
}
private static BufferChar[] ReadBufferLines(int top, int count)
{
return _singleton._console.ReadBufferLines(top, count);
}
private void GetTokenColors(Token token, out ConsoleColor foregroundColor, out ConsoleColor backgroundColor)
{
switch (token.Kind)
{
case TokenKind.Comment:
foregroundColor = _options.CommentForegroundColor;
backgroundColor = _options.CommentBackgroundColor;
return;
case TokenKind.Parameter:
foregroundColor = _options.ParameterForegroundColor;
backgroundColor = _options.ParameterBackgroundColor;
return;
case TokenKind.Variable:
case TokenKind.SplattedVariable:
foregroundColor = _options.VariableForegroundColor;
backgroundColor = _options.VariableBackgroundColor;
return;
case TokenKind.StringExpandable:
case TokenKind.StringLiteral:
case TokenKind.HereStringExpandable:
case TokenKind.HereStringLiteral:
foregroundColor = _options.StringForegroundColor;
backgroundColor = _options.StringBackgroundColor;
return;
case TokenKind.Number:
foregroundColor = _options.NumberForegroundColor;
backgroundColor = _options.NumberBackgroundColor;
return;
}
if ((token.TokenFlags & TokenFlags.CommandName) != 0)
{
foregroundColor = _options.CommandForegroundColor;
backgroundColor = _options.CommandBackgroundColor;
return;
}
if ((token.TokenFlags & TokenFlags.Keyword) != 0)
{
foregroundColor = _options.KeywordForegroundColor;
backgroundColor = _options.KeywordBackgroundColor;
return;
}
if ((token.TokenFlags & (TokenFlags.BinaryOperator | TokenFlags.UnaryOperator | TokenFlags.AssignmentOperator)) != 0)
{
foregroundColor = _options.OperatorForegroundColor;
backgroundColor = _options.OperatorBackgroundColor;
return;
}
if ((token.TokenFlags & TokenFlags.TypeName) != 0)
{
foregroundColor = _options.TypeForegroundColor;
backgroundColor = _options.TypeBackgroundColor;
return;
}
if ((token.TokenFlags & TokenFlags.MemberName) != 0)
{
foregroundColor = _options.MemberForegroundColor;
backgroundColor = _options.MemberBackgroundColor;
return;
}
foregroundColor = _options.DefaultTokenForegroundColor;
backgroundColor = _options.DefaultTokenBackgroundColor;
}
private void GetRegion(out int start, out int length)
{
if (_mark < _current)
{
start = _mark;
length = _current - start;
}
else
{
start = _current;
length = _mark - start;
}
}
private bool InRegion(int i)
{
int start, end;
if (_mark > _current)
{
start = _current;
end = _mark;
}
else
{
start = _mark;
end = _current;
}
return i >= start && i < end;
}
private void MaybeEmphasize(ref BufferChar charInfo, int i, ConsoleColor foregroundColor, ConsoleColor backgroundColor)
{
if (i >= _emphasisStart && i < (_emphasisStart + _emphasisLength))
{
backgroundColor = _options.EmphasisBackgroundColor;
foregroundColor = _options.EmphasisForegroundColor;
}
else if (_visualSelectionCommandCount > 0 && InRegion(i))
{
// We can't quite emulate real console selection because it inverts
// based on actual screen colors, our palette is limited. The choice
// to invert only the lower 3 bits to change the color is somewhat
// but looks best with the 2 default color schemes - starting PowerShell
// from it's shortcut or from a cmd shortcut.
#if UNIX // TODO: set Inverse attribute and let render choose what to do.
ConsoleColor tempColor = (foregroundColor == UnknownColor) ? ConsoleColor.White : foregroundColor;
foregroundColor = (backgroundColor == UnknownColor) ? ConsoleColor.Black : backgroundColor;
backgroundColor = tempColor;
#else
foregroundColor = (ConsoleColor)((int)foregroundColor ^ 7);
backgroundColor = (ConsoleColor)((int)backgroundColor ^ 7);
#endif
}
charInfo.ForegroundColor = foregroundColor;
charInfo.BackgroundColor = backgroundColor;
}
private void PlaceCursor(int x, ref int y)
{
int statusLineCount = GetStatusLineCount();
if ((y + statusLineCount) >= _console.BufferHeight)
{
_console.ScrollBuffer((y + statusLineCount) - _console.BufferHeight + 1);
y = _console.BufferHeight - 1;
}
_console.SetCursorPosition(x, y);
}
private void PlaceCursor()
{
var coordinates = ConvertOffsetToCoordinates(_current);
int y = coordinates.Y;
PlaceCursor(coordinates.X, ref y);
}
private COORD ConvertOffsetToCoordinates(int offset)
{
int x = _initialX;
int y = _initialY + Options.ExtraPromptLineCount;
int bufferWidth = _console.BufferWidth;
var continuationPromptLength = Options.ContinuationPrompt.Length;
for (int i = 0; i < offset; i++)
{
char c = _buffer[i];
if (c == '\n')
{
y += 1;
x = continuationPromptLength;
}
else
{
int size = LengthInBufferCells(c);
x += size;
// Wrap? No prompt when wrapping
if (x >= bufferWidth)
{
int offsize = x - bufferWidth;
if (offsize % size == 0)
{
x -= bufferWidth;
}
else
{
x = size;
}
y += 1;
}
}
}
//if the next character has bigger size than the remain space on this line,
//the cursor goes to next line where the next character is.
if (_buffer.Length > offset)
{
int size = LengthInBufferCells(_buffer[offset]);
// next one is Wrapped to next line
if (x + size > bufferWidth && (x + size - bufferWidth) % size != 0)
{
x = 0;
y++;
}
}
return new COORD {X = (short)x, Y = (short)y};
}
private int ConvertOffsetToConsoleBufferOffset(int offset, int startIndex)
{
int j = startIndex;
for (int i = 0; i < offset; i++)
{
var c = _buffer[i];
if (c == '\n')
{
for (int k = 0; k < Options.ContinuationPrompt.Length; k++)
{
j++;
}
}
else if (LengthInBufferCells(c) > 1)
{
j += 2;
}
else
{
j++;
}
}
return j;
}
private int ConvertLineAndColumnToOffset(COORD coord)
{
int offset;
int x = _initialX;
int y = _initialY + Options.ExtraPromptLineCount;
int bufferWidth = _console.BufferWidth;
var continuationPromptLength = Options.ContinuationPrompt.Length;
for (offset = 0; offset < _buffer.Length; offset++)
{
// If we are on the correct line, return when we find
// the correct column
if (coord.Y == y && coord.X <= x)
{
return offset;
}
char c = _buffer[offset];
if (c == '\n')
{
// If we are about to move off of the correct line,
// the line was shorter than the column we wanted so return.
if (coord.Y == y)
{
return offset;
}
y += 1;
x = continuationPromptLength;
}
else
{
int size = LengthInBufferCells(c);
x += size;
// Wrap? No prompt when wrapping
if (x >= bufferWidth)
{
int offsize = x - bufferWidth;
if (offsize % size == 0)
{
x -= bufferWidth;
}
else
{
x = size;
}
y += 1;
}
}
}
// Return -1 if y is out of range, otherwise the last line was shorter
// than we wanted, but still in range so just return the last offset.
return (coord.Y == y) ? offset : -1;
}
private bool LineIsMultiLine()
{
for (int i = 0; i < _buffer.Length; i++)
{
if (_buffer[i] == '\n')
return true;
}
return false;
}
private int GetStatusLineCount()
{
if (_statusLinePrompt == null)
return 0;
return (_statusLinePrompt.Length + _statusBuffer.Length) / _console.BufferWidth + 1;
}
[ExcludeFromCodeCoverage]
void IPSConsoleReadLineMockableMethods.Ding()
{
switch (Options.BellStyle)
{
case BellStyle.None:
break;
case BellStyle.Audible:
#if UNIX
Console.Beep();
#else
Console.Beep(Options.DingTone, Options.DingDuration);
#endif
break;
case BellStyle.Visual:
// TODO: flash prompt? command line?
break;
}
}
/// <summary>
/// Notify the user based on their preference for notification.
/// </summary>
public static void Ding()
{
_singleton._mockableMethods.Ding();
}
private bool PromptYesOrNo(string s)
{
_statusLinePrompt = s;
Render();
var key = ReadKey();
_statusLinePrompt = null;
Render();
return key.Key == ConsoleKey.Y;
}
#region Screen scrolling
#if !UNIX
/// <summary>
/// Scroll the display up one screen.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ScrollDisplayUp(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
TryGetArgAsInt(arg, out numericArg, +1);
var console = _singleton._console;
var newTop = console.WindowTop - (numericArg * console.WindowHeight);
if (newTop < 0)
{
newTop = 0;
}
console.SetWindowPosition(0, newTop);
}
/// <summary>
/// Scroll the display up one line.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ScrollDisplayUpLine(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
TryGetArgAsInt(arg, out numericArg, +1);
var console = _singleton._console;
var newTop = console.WindowTop - numericArg;
if (newTop < 0)
{
newTop = 0;
}
console.SetWindowPosition(0, newTop);
}
/// <summary>
/// Scroll the display down one screen.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ScrollDisplayDown(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
TryGetArgAsInt(arg, out numericArg, +1);
var console = _singleton._console;
var newTop = console.WindowTop + (numericArg * console.WindowHeight);
if (newTop > (console.BufferHeight - console.WindowHeight))
{
newTop = (console.BufferHeight - console.WindowHeight);
}
console.SetWindowPosition(0, newTop);
}
/// <summary>
/// Scroll the display down one line.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ScrollDisplayDownLine(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
TryGetArgAsInt(arg, out numericArg, +1);
var console = _singleton._console;
var newTop = console.WindowTop + numericArg;
if (newTop > (console.BufferHeight - console.WindowHeight))
{
newTop = (console.BufferHeight - console.WindowHeight);
}
console.SetWindowPosition(0, newTop);
}
/// <summary>
/// Scroll the display to the top.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ScrollDisplayTop(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton._console.SetWindowPosition(0, 0);
}
/// <summary>
/// Scroll the display to the cursor.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void ScrollDisplayToCursor(ConsoleKeyInfo? key = null, object arg = null)
{
// Ideally, we'll put the last input line at the bottom of the window
var coordinates = _singleton.ConvertOffsetToCoordinates(_singleton._buffer.Length);
var console = _singleton._console;
var newTop = coordinates.Y - console.WindowHeight + 1;
// If the cursor is already visible, and we're on the first
// page-worth of the buffer, then just scroll to the top (we can't
// scroll to before the beginning of the buffer).
//
// Note that we don't want to just return, because the window may
// have been scrolled way past the end of the content, so we really
// do need to set the new window top to 0 to bring it back into
// view.
if (newTop < 0)
{
newTop = 0;
}
// But if the cursor won't be visible, make sure it is.
if (newTop > console.CursorTop)
{
// Add 10 for some extra context instead of putting the
// cursor on the bottom line.
newTop = console.CursorTop - console.WindowHeight + 10;
}
// But we can't go past the end of the buffer.
if (newTop > (console.BufferHeight - console.WindowHeight))
{
newTop = (console.BufferHeight - console.WindowHeight);
}
console.SetWindowPosition(0, newTop);
}
#endif
#endregion Screen scrolling
}
}

View file

@ -1,350 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Language;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
private static void ViReplaceUntilEsc(ConsoleKeyInfo? key, object arg)
{
if (_singleton._current >= _singleton._buffer.Length)
{
Ding();
return;
}
int startingCursor = _singleton._current;
int maxDeleteLength = _singleton._buffer.Length - _singleton._current;
StringBuilder deletedStr = new StringBuilder();
ConsoleKeyInfo nextKey = ReadKey();
while (nextKey.Key != ConsoleKey.Escape && nextKey.Key != ConsoleKey.Enter)
{
if (nextKey.Key != ConsoleKey.Backspace && nextKey.KeyChar != '\u0000')
{
if (_singleton._current >= _singleton._buffer.Length)
{
_singleton._buffer.Append(nextKey.KeyChar);
}
else
{
deletedStr.Append(_singleton._buffer[_singleton._current]);
_singleton._buffer[_singleton._current] = nextKey.KeyChar;
}
_singleton._current++;
_singleton.Render();
}
if (nextKey.Key == ConsoleKey.Backspace)
{
if (_singleton._current == startingCursor)
{
Ding();
}
else
{
if (deletedStr.Length == _singleton._current - startingCursor)
{
_singleton._buffer[_singleton._current - 1] = deletedStr[deletedStr.Length - 1];
deletedStr.Remove(deletedStr.Length - 1, 1);
}
else
{
_singleton._buffer.Remove(_singleton._current - 1, 1);
}
_singleton._current--;
_singleton.Render();
}
}
nextKey = ReadKey();
}
if (_singleton._current > startingCursor)
{
_singleton.StartEditGroup();
string insStr = _singleton._buffer.ToString(startingCursor, _singleton._current - startingCursor);
_singleton.SaveEditItem(EditItemDelete.Create(deletedStr.ToString(), startingCursor));
_singleton.SaveEditItem(EditItemInsertString.Create(insStr, startingCursor));
_singleton.EndEditGroup();
}
if (nextKey.Key == ConsoleKey.Enter)
{
ViAcceptLine(nextKey);
}
}
private static void ViReplaceBrace(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(ViReplaceBrace, arg);
ViDeleteBrace(key, arg);
ViInsertMode(key, arg);
}
private static void ViBackwardReplaceLineToFirstChar(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(ViBackwardReplaceLineToFirstChar, arg);
DeleteLineToFirstChar(key, arg);
ViInsertMode(key, arg);
}
private static void ViBackwardReplaceLine(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(ViBackwardReplaceLine, arg);
BackwardDeleteLine(key, arg);
ViInsertMode(key, arg);
}
private static void BackwardReplaceChar(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(BackwardReplaceChar, arg);
BackwardDeleteChar(key, arg);
ViInsertMode(key, arg);
}
private static void ViBackwardReplaceWord(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(ViBackwardReplaceWord, arg);
BackwardDeleteWord(key, arg);
ViInsertMode(key, arg);
}
private static void ViBackwardReplaceGlob(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(ViBackwardReplaceGlob, arg);
ViBackwardDeleteGlob(key, arg);
ViInsertMode(key, arg);
}
private static void ViReplaceToEnd(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(ViReplaceToEnd, arg);
DeleteToEnd(key, arg);
_singleton._current = Math.Min(_singleton._buffer.Length, _singleton._current + 1);
_singleton.PlaceCursor();
ViInsertMode(key, arg);
}
private static void ViReplaceLine(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(ViReplaceLine, arg);
DeleteLine(key, arg);
ViInsertMode(key, arg);
}
private static void ViReplaceWord(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(ViReplaceWord, arg);
_singleton._lastWordDelimiter = char.MinValue;
_singleton._shouldAppend = false;
DeleteWord(key, arg);
if (_singleton._current < _singleton._buffer.Length - 1)
{
if (char.IsWhiteSpace(_singleton._lastWordDelimiter))
{
Insert(_singleton._lastWordDelimiter);
_singleton._current--;
}
_singleton._lastWordDelimiter = char.MinValue;
_singleton.PlaceCursor();
}
if (_singleton._current == _singleton._buffer.Length - 1
&& !_singleton.IsDelimiter(_singleton._lastWordDelimiter, _singleton.Options.WordDelimiters)
&& _singleton._shouldAppend)
{
ViInsertWithAppend(key, arg);
}
else
{
ViInsertMode(key, arg);
}
}
private static void ViReplaceGlob(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(ViReplaceGlob, arg);
ViDeleteGlob(key, arg);
if (_singleton._current < _singleton._buffer.Length - 1)
{
Insert(' ');
_singleton._current--;
_singleton.PlaceCursor();
}
if (_singleton._current == _singleton._buffer.Length - 1)
{
ViInsertWithAppend(key, arg);
}
else
{
ViInsertMode(key, arg);
}
}
private static void ViReplaceEndOfWord(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(ViReplaceEndOfWord, arg);
DeleteEndOfWord(key, arg);
if (_singleton._current == _singleton._buffer.Length - 1)
{
ViInsertWithAppend(key, arg);
}
else
{
ViInsertMode(key, arg);
}
}
private static void ViReplaceEndOfGlob(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(ViReplaceEndOfGlob, arg);
ViDeleteEndOfGlob(key, arg);
if (_singleton._current == _singleton._buffer.Length - 1)
{
ViInsertWithAppend(key, arg);
}
else
{
ViInsertMode(key, arg);
}
}
private static void ReplaceChar(ConsoleKeyInfo? key, object arg)
{
_singleton._groupUndoHelper.StartGroup(ReplaceChar, arg);
DeleteChar(key, arg);
ViInsertMode(key, arg);
}
/// <summary>
/// Replaces the current character with the next character typed.
/// </summary>
private static void ReplaceCharInPlace(ConsoleKeyInfo? key, object arg)
{
ConsoleKeyInfo nextKey = ReadKey();
if (_singleton._buffer.Length > 0 && nextKey.KeyChar > 0 && nextKey.Key != ConsoleKey.Escape && nextKey.Key != ConsoleKey.Enter)
{
_singleton.StartEditGroup();
_singleton.SaveEditItem(EditItemDelete.Create(_singleton._buffer[_singleton._current].ToString(), _singleton._current));
_singleton.SaveEditItem(EditItemInsertString.Create(nextKey.KeyChar.ToString(), _singleton._current));
_singleton.EndEditGroup();
_singleton._buffer[_singleton._current] = nextKey.KeyChar;
_singleton.Render();
}
else
{
Ding();
}
}
/// <summary>
/// Deletes until given character
/// </summary>
/// <param name="key"></param>
/// <param name="arg"></param>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
private static void ViReplaceToChar(ConsoleKeyInfo? key = null, object arg = null)
{
var keyChar = ReadKey().KeyChar;
ViReplaceToChar(keyChar, key, arg);
}
private static void ViReplaceToChar(char keyChar, ConsoleKeyInfo? key = null, object arg = null)
{
bool shouldAppend = _singleton._current > 0;
_singleton._groupUndoHelper.StartGroup(ReplaceChar, arg);
ViCharacterSearcher.Set(keyChar, isBackward: false, isBackoff: false);
if (ViCharacterSearcher.SearchDelete(keyChar, arg, backoff: false, instigator: (_key, _arg) => ViReplaceToChar(keyChar, _key, _arg)))
{
if (shouldAppend)
{
ViInsertWithAppend(key, arg);
}
else
{
ViInsertMode(key, arg);
}
}
}
/// <summary>
/// Replaces until given character
/// </summary>
/// <param name="key"></param>
/// <param name="arg"></param>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
private static void ViReplaceToCharBackward(ConsoleKeyInfo? key = null, object arg = null)
{
var keyChar = ReadKey().KeyChar;
ViReplaceToCharBack(keyChar, key, arg);
}
private static void ViReplaceToCharBack(char keyChar, ConsoleKeyInfo? key = null, object arg = null)
{
_singleton._groupUndoHelper.StartGroup(ReplaceChar, arg);
if (ViCharacterSearcher.SearchBackwardDelete(keyChar, arg, backoff: false, instigator: (_key, _arg) => ViReplaceToCharBack(keyChar, _key, _arg)))
{
ViInsertMode(key, arg);
}
}
/// <summary>
/// Replaces until given character
/// </summary>
/// <param name="key"></param>
/// <param name="arg"></param>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
private static void ViReplaceToBeforeChar(ConsoleKeyInfo? key = null, object arg = null)
{
var keyChar = ReadKey().KeyChar;
ViReplaceToBeforeChar(keyChar, key, arg);
}
private static void ViReplaceToBeforeChar(char keyChar, ConsoleKeyInfo? key = null, object arg = null)
{
_singleton._groupUndoHelper.StartGroup(ReplaceChar, arg);
ViCharacterSearcher.Set(keyChar, isBackward: false, isBackoff: true);
if (ViCharacterSearcher.SearchDelete(keyChar, arg, backoff: true, instigator: (_key, _arg) => ViReplaceToBeforeChar(keyChar, _key, _arg)))
{
ViInsertMode(key, arg);
}
}
/// <summary>
/// Replaces until given character
/// </summary>
/// <param name="key"></param>
/// <param name="arg"></param>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
private static void ViReplaceToBeforeCharBackward(ConsoleKeyInfo? key = null, object arg = null)
{
var keyChar = ReadKey().KeyChar;
ViReplaceToBeforeCharBack(keyChar, key, arg);
}
private static void ViReplaceToBeforeCharBack(char keyChar, ConsoleKeyInfo? key = null, object arg = null)
{
_singleton._groupUndoHelper.StartGroup(ReplaceChar, arg);
if (ViCharacterSearcher.SearchBackwardDelete(keyChar, arg, backoff: true, instigator: (_key, _arg) => ViReplaceToBeforeCharBack(keyChar, _key, _arg)))
{
ViInsertMode(key, arg);
}
}
}
}

View file

@ -1,491 +0,0 @@
# This is an example profile for PSReadline.
#
# This is roughly what I use so there is some emphasis on emacs bindings,
# but most of these bindings make sense in Windows mode as well.
Import-Module PSReadLine
Set-PSReadLineOption -EditMode Emacs
# Searching for commands with up/down arrow is really handy. The
# option "moves to end" is useful if you want the cursor at the end
# of the line while cycling through history like it does w/o searching,
# without that option, the cursor will remain at the position it was
# when you used up arrow, which can be useful if you forget the exact
# string you started the search on.
Set-PSReadLineOption -HistorySearchCursorMovesToEnd
Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward
# This key handler shows the entire or filtered history using Out-GridView. The
# typed text is used as the substring pattern for filtering. A selected command
# is inserted to the command line without invoking. Multiple command selection
# is supported, e.g. selected by Ctrl + Click.
Set-PSReadlineKeyHandler -Key F7 `
-BriefDescription History `
-LongDescription 'Show command history' `
-ScriptBlock {
$pattern = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$pattern, [ref]$null)
if ($pattern)
{
$pattern = [regex]::Escape($pattern)
}
$history = [System.Collections.ArrayList]@(
$last = ''
$lines = ''
foreach ($line in [System.IO.File]::ReadLines((Get-PSReadlineOption).HistorySavePath))
{
if ($line.EndsWith('`'))
{
$line = $line.Substring(0, $line.Length - 1)
$lines = if ($lines)
{
"$lines`n$line"
}
else
{
$line
}
continue
}
if ($lines)
{
$line = "$lines`n$line"
$lines = ''
}
if (($line -cne $last) -and (!$pattern -or ($line -match $pattern)))
{
$last = $line
$line
}
}
)
$history.Reverse()
$command = $history | Out-GridView -Title History -PassThru
if ($command)
{
[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
[Microsoft.PowerShell.PSConsoleReadLine]::Insert(($command -join "`n"))
}
}
# This is an example of a macro that you might use to execute a command.
# This will add the command to history.
Set-PSReadlineKeyHandler -Key Ctrl+B `
-BriefDescription BuildCurrentDirectory `
-LongDescription "Build the current directory" `
-ScriptBlock {
[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
[Microsoft.PowerShell.PSConsoleReadLine]::Insert("msbuild")
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
}
# In Emacs mode - Tab acts like in bash, but the Windows style completion
# is still useful sometimes, so bind some keys so we can do both
Set-PSReadlineKeyHandler -Key Ctrl+Q -Function TabCompleteNext
Set-PSReadlineKeyHandler -Key Ctrl+Shift+Q -Function TabCompletePrevious
# Clipboard interaction is bound by default in Windows mode, but not Emacs mode.
Set-PSReadlineKeyHandler -Key Shift+Ctrl+C -Function Copy
Set-PSReadlineKeyHandler -Key Ctrl+V -Function Paste
# CaptureScreen is good for blog posts or email showing a transaction
# of what you did when asking for help or demonstrating a technique.
Set-PSReadlineKeyHandler -Chord 'Ctrl+D,Ctrl+C' -Function CaptureScreen
# The built-in word movement uses character delimiters, but token based word
# movement is also very useful - these are the bindings you'd use if you
# prefer the token based movements bound to the normal emacs word movement
# key bindings.
Set-PSReadlineKeyHandler -Key Alt+D -Function ShellKillWord
Set-PSReadlineKeyHandler -Key Alt+Backspace -Function ShellBackwardKillWord
Set-PSReadlineKeyHandler -Key Alt+B -Function ShellBackwardWord
Set-PSReadlineKeyHandler -Key Alt+F -Function ShellForwardWord
Set-PSReadlineKeyHandler -Key Shift+Alt+B -Function SelectShellBackwardWord
Set-PSReadlineKeyHandler -Key Shift+Alt+F -Function SelectShellForwardWord
#region Smart Insert/Delete
# The next four key handlers are designed to make entering matched quotes
# parens, and braces a nicer experience. I'd like to include functions
# in the module that do this, but this implementation still isn't as smart
# as ReSharper, so I'm just providing it as a sample.
Set-PSReadlineKeyHandler -Key '"',"'" `
-BriefDescription SmartInsertQuote `
-LongDescription "Insert paired quotes if not already on a quote" `
-ScriptBlock {
param($key, $arg)
$line = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
if ($line[$cursor] -eq $key.KeyChar) {
# Just move the cursor
[Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1)
}
else {
# Insert matching quotes, move cursor to be in between the quotes
[Microsoft.PowerShell.PSConsoleReadLine]::Insert("$($key.KeyChar)" * 2)
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
[Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor - 1)
}
}
Set-PSReadlineKeyHandler -Key '(','{','[' `
-BriefDescription InsertPairedBraces `
-LongDescription "Insert matching braces" `
-ScriptBlock {
param($key, $arg)
$closeChar = switch ($key.KeyChar)
{
<#case#> '(' { [char]')'; break }
<#case#> '{' { [char]'}'; break }
<#case#> '[' { [char]']'; break }
}
[Microsoft.PowerShell.PSConsoleReadLine]::Insert("$($key.KeyChar)$closeChar")
$line = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
[Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor - 1)
}
Set-PSReadlineKeyHandler -Key ')',']','}' `
-BriefDescription SmartCloseBraces `
-LongDescription "Insert closing brace or skip" `
-ScriptBlock {
param($key, $arg)
$line = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
if ($line[$cursor] -eq $key.KeyChar)
{
[Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1)
}
else
{
[Microsoft.PowerShell.PSConsoleReadLine]::Insert("$($key.KeyChar)")
}
}
Set-PSReadlineKeyHandler -Key Backspace `
-BriefDescription SmartBackspace `
-LongDescription "Delete previous character or matching quotes/parens/braces" `
-ScriptBlock {
param($key, $arg)
$line = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
if ($cursor -gt 0)
{
$toMatch = $null
if ($cursor -lt $line.Length)
{
switch ($line[$cursor])
{
<#case#> '"' { $toMatch = '"'; break }
<#case#> "'" { $toMatch = "'"; break }
<#case#> ')' { $toMatch = '('; break }
<#case#> ']' { $toMatch = '['; break }
<#case#> '}' { $toMatch = '{'; break }
}
}
if ($null -ne $toMatch -and $line[$cursor-1] -eq $toMatch)
{
[Microsoft.PowerShell.PSConsoleReadLine]::Delete($cursor - 1, 2)
}
else
{
[Microsoft.PowerShell.PSConsoleReadLine]::BackwardDeleteChar($key, $arg)
}
}
}
#endregion Smart Insert/Delete
# Sometimes you enter a command but realize you forgot to do something else first.
# This binding will let you save that command in the history so you can recall it,
# but it doesn't actually execute. It also clears the line with RevertLine so the
# undo stack is reset - though redo will still reconstruct the command line.
Set-PSReadlineKeyHandler -Key Alt+w `
-BriefDescription SaveInHistory `
-LongDescription "Save current line in history but do not execute" `
-ScriptBlock {
param($key, $arg)
$line = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
[Microsoft.PowerShell.PSConsoleReadLine]::AddToHistory($line)
[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
}
# Insert text from the clipboard as a here string
Set-PSReadlineKeyHandler -Key Ctrl+Shift+v `
-BriefDescription PasteAsHereString `
-LongDescription "Paste the clipboard text as a here string" `
-ScriptBlock {
param($key, $arg)
Add-Type -Assembly PresentationCore
if ([System.Windows.Clipboard]::ContainsText())
{
# Get clipboard text - remove trailing spaces, convert \r\n to \n, and remove the final \n.
$text = ([System.Windows.Clipboard]::GetText() -replace "\p{Zs}*`r?`n","`n").TrimEnd()
[Microsoft.PowerShell.PSConsoleReadLine]::Insert("@'`n$text`n'@")
}
else
{
[Microsoft.PowerShell.PSConsoleReadLine]::Ding()
}
}
# Sometimes you want to get a property of invoke a member on what you've entered so far
# but you need parens to do that. This binding will help by putting parens around the current selection,
# or if nothing is selected, the whole line.
Set-PSReadlineKeyHandler -Key 'Alt+(' `
-BriefDescription ParenthesizeSelection `
-LongDescription "Put parenthesis around the selection or entire line and move the cursor to after the closing parenthesis" `
-ScriptBlock {
param($key, $arg)
$selectionStart = $null
$selectionLength = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetSelectionState([ref]$selectionStart, [ref]$selectionLength)
$line = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
if ($selectionStart -ne -1)
{
[Microsoft.PowerShell.PSConsoleReadLine]::Replace($selectionStart, $selectionLength, '(' + $line.SubString($selectionStart, $selectionLength) + ')')
[Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($selectionStart + $selectionLength + 2)
}
else
{
[Microsoft.PowerShell.PSConsoleReadLine]::Replace(0, $line.Length, '(' + $line + ')')
[Microsoft.PowerShell.PSConsoleReadLine]::EndOfLine()
}
}
# Each time you press Alt+', this key handler will change the token
# under or before the cursor. It will cycle through single quotes, double quotes, or
# no quotes each time it is invoked.
Set-PSReadlineKeyHandler -Key "Alt+'" `
-BriefDescription ToggleQuoteArgument `
-LongDescription "Toggle quotes on the argument under the cursor" `
-ScriptBlock {
param($key, $arg)
$ast = $null
$tokens = $null
$errors = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$errors, [ref]$cursor)
$tokenToChange = $null
foreach ($token in $tokens)
{
$extent = $token.Extent
if ($extent.StartOffset -le $cursor -and $extent.EndOffset -ge $cursor)
{
$tokenToChange = $token
# If the cursor is at the end (it's really 1 past the end) of the previous token,
# we only want to change the previous token if there is no token under the cursor
if ($extent.EndOffset -eq $cursor -and $foreach.MoveNext())
{
$nextToken = $foreach.Current
if ($nextToken.Extent.StartOffset -eq $cursor)
{
$tokenToChange = $nextToken
}
}
break
}
}
if ($null -ne $tokenToChange)
{
$extent = $tokenToChange.Extent
$tokenText = $extent.Text
if ($tokenText[0] -eq '"' -and $tokenText[-1] -eq '"')
{
# Switch to no quotes
$replacement = $tokenText.Substring(1, $tokenText.Length - 2)
}
elseif ($tokenText[0] -eq "'" -and $tokenText[-1] -eq "'")
{
# Switch to double quotes
$replacement = '"' + $tokenText.Substring(1, $tokenText.Length - 2) + '"'
}
else
{
# Add single quotes
$replacement = "'" + $tokenText + "'"
}
[Microsoft.PowerShell.PSConsoleReadLine]::Replace(
$extent.StartOffset,
$tokenText.Length,
$replacement)
}
}
# This example will replace any aliases on the command line with the resolved commands.
Set-PSReadlineKeyHandler -Key "Alt+%" `
-BriefDescription ExpandAliases `
-LongDescription "Replace all aliases with the full command" `
-ScriptBlock {
param($key, $arg)
$ast = $null
$tokens = $null
$errors = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$errors, [ref]$cursor)
$startAdjustment = 0
foreach ($token in $tokens)
{
if ($token.TokenFlags -band [System.Management.Automation.Language.TokenFlags]::CommandName)
{
$alias = $ExecutionContext.InvokeCommand.GetCommand($token.Extent.Text, 'Alias')
if ($null -ne $alias)
{
$resolvedCommand = $alias.ResolvedCommandName
if ($null -ne $resolvedCommand)
{
$extent = $token.Extent
$length = $extent.EndOffset - $extent.StartOffset
[Microsoft.PowerShell.PSConsoleReadLine]::Replace(
$extent.StartOffset + $startAdjustment,
$length,
$resolvedCommand)
# Our copy of the tokens won't have been updated, so we need to
# adjust by the difference in length
$startAdjustment += ($resolvedCommand.Length - $length)
}
}
}
}
}
# F1 for help on the command line - naturally
Set-PSReadlineKeyHandler -Key F1 `
-BriefDescription CommandHelp `
-LongDescription "Open the help window for the current command" `
-ScriptBlock {
param($key, $arg)
$ast = $null
$tokens = $null
$errors = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$errors, [ref]$cursor)
$commandAst = $ast.FindAll( {
$node = $args[0]
$node -is [System.Management.Automation.Language.CommandAst] -and
$node.Extent.StartOffset -le $cursor -and
$node.Extent.EndOffset -ge $cursor
}, $true) | Select-Object -Last 1
if ($null -ne $commandAst)
{
$commandName = $commandAst.GetCommandName()
if ($null -ne $commandName)
{
$command = $ExecutionContext.InvokeCommand.GetCommand($commandName, 'All')
if ($command -is [System.Management.Automation.AliasInfo])
{
$commandName = $command.ResolvedCommandName
}
if ($null -ne $commandName)
{
Get-Help $commandName -ShowWindow
}
}
}
}
#
# Ctrl+Shift+j then type a key to mark the current directory.
# Ctrj+j then the same key will change back to that directory without
# needing to type cd and won't change the command line.
#
$global:PSReadlineMarks = @{}
Set-PSReadlineKeyHandler -Key Ctrl+Shift+j `
-BriefDescription MarkDirectory `
-LongDescription "Mark the current directory" `
-ScriptBlock {
param($key, $arg)
$key = [Console]::ReadKey($true)
$global:PSReadlineMarks[$key.KeyChar] = $pwd
}
Set-PSReadlineKeyHandler -Key Ctrl+j `
-BriefDescription JumpDirectory `
-LongDescription "Goto the marked directory" `
-ScriptBlock {
param($key, $arg)
$key = [Console]::ReadKey()
$dir = $global:PSReadlineMarks[$key.KeyChar]
if ($dir)
{
cd $dir
[Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt()
}
}
Set-PSReadlineKeyHandler -Key Alt+j `
-BriefDescription ShowDirectoryMarks `
-LongDescription "Show the currently marked directories" `
-ScriptBlock {
param($key, $arg)
$global:PSReadlineMarks.GetEnumerator() | ForEach-Object {
[PSCustomObject]@{Key = $_.Key; Dir = $_.Value} } |
Format-Table -AutoSize | Out-Host
[Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt()
}
Set-PSReadlineOption -CommandValidationHandler {
param([System.Management.Automation.Language.CommandAst]$CommandAst)
switch ($CommandAst.GetCommandName())
{
'git' {
$gitCmd = $CommandAst.CommandElements[1].Extent
switch ($gitCmd.Text)
{
'cmt' {
[Microsoft.PowerShell.PSConsoleReadLine]::Replace(
$gitCmd.StartOffset, $gitCmd.EndOffset - $gitCmd.StartOffset, 'commit')
}
}
}
}
}

View file

@ -1,309 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
#if !UNIX
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.PowerShell.Internal;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
private static void InvertLines(int start, int count)
{
var buffer = ReadBufferLines(start, count);
for (int i = 0; i < buffer.Length; i++)
{
buffer[i].ForegroundColor = (ConsoleColor)((int)buffer[i].ForegroundColor ^ 7);
buffer[i].BackgroundColor = (ConsoleColor)((int)buffer[i].BackgroundColor ^ 7);
}
_singleton._console.WriteBufferLines(buffer, ref start, false);
}
/// <summary>
/// Start interactive screen capture - up/down arrows select lines, enter copies
/// selected text to clipboard as text and html
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void CaptureScreen(ConsoleKeyInfo? key = null, object arg = null)
{
int selectionTop = _singleton._console.CursorTop;
int selectionHeight = 1;
int currentY = selectionTop;
Internal.IConsole console = _singleton._console;
// We'll keep the current selection line (currentY) at least 4 lines
// away from the top or bottom of the window.
const int margin = 5;
Func<bool> tooCloseToTop = () => { return (currentY - console.WindowTop) < margin; };
Func<bool> tooCloseToBottom = () => { return ((console.WindowTop + console.WindowHeight) - currentY) < margin; };
// Current lines starts out selected
InvertLines(selectionTop, selectionHeight);
bool done = false;
while (!done)
{
var k = ReadKey();
switch (k.Key)
{
case ConsoleKey.K:
case ConsoleKey.UpArrow:
if (tooCloseToTop())
ScrollDisplayUpLine();
if (currentY > 0)
{
currentY -= 1;
if ((k.Modifiers & ConsoleModifiers.Shift) == ConsoleModifiers.Shift)
{
if (currentY < selectionTop)
{
// Extend selection up, only invert newly selected line.
InvertLines(currentY, 1);
selectionTop = currentY;
selectionHeight += 1;
}
else if (currentY >= selectionTop)
{
// Selection shortend 1 line, invert unselected line.
InvertLines(currentY + 1, 1);
selectionHeight -= 1;
}
break;
}
goto updateSelectionCommon;
}
break;
case ConsoleKey.J:
case ConsoleKey.DownArrow:
if (tooCloseToBottom())
ScrollDisplayDownLine();
if (currentY < (console.BufferHeight - 1))
{
currentY += 1;
if ((k.Modifiers & ConsoleModifiers.Shift) == ConsoleModifiers.Shift)
{
if (currentY == (selectionTop + selectionHeight))
{
// Extend selection down, only invert newly selected line.
InvertLines(selectionTop + selectionHeight, 1);
selectionHeight += 1;
}
else if (currentY == (selectionTop + 1))
{
// Selection shortend 1 line, invert unselected line.
InvertLines(selectionTop, 1);
selectionTop = currentY;
selectionHeight -= 1;
}
break;
}
goto updateSelectionCommon;
}
break;
updateSelectionCommon:
// Shift not pressed - unselect current selection
InvertLines(selectionTop, selectionHeight);
selectionTop = currentY;
selectionHeight = 1;
InvertLines(selectionTop, selectionHeight);
break;
case ConsoleKey.Enter:
InvertLines(selectionTop, selectionHeight);
DumpScreenToClipboard(selectionTop, selectionHeight);
ScrollDisplayToCursor();
return;
case ConsoleKey.Escape:
done = true;
continue;
case ConsoleKey.C:
case ConsoleKey.G:
if (k.Modifiers == ConsoleModifiers.Control)
{
done = true;
continue;
}
Ding();
break;
default:
Ding();
break;
}
}
InvertLines(selectionTop, selectionHeight);
ScrollDisplayToCursor();
}
private const string CmdColorTable = @"
\red0\green0\blue0;
\red0\green0\blue128;
\red0\green128\blue0;
\red0\green128\blue128;
\red128\green0\blue0;
\red128\green0\blue128;
\red128\green128\blue0;
\red192\green192\blue192;
\red128\green128\blue128;
\red0\green0\blue255;
\red0\green255\blue0;
\red0\green255\blue255;
\red255\green0\blue0;
\red255\green0\blue255;
\red255\green255\blue0;
\red255\green255\blue255;
";
private const string PowerShellColorTable = @"
\red1\green36\blue86;
\red0\green0\blue128;
\red0\green128\blue0;
\red0\green128\blue128;
\red128\green0\blue0;
\red1\green36\blue86;
\red238\green237\blue240;
\red192\green192\blue192;
\red128\green128\blue128;
\red0\green0\blue255;
\red0\green255\blue0;
\red0\green255\blue255;
\red255\green0\blue0;
\red255\green0\blue255;
\red255\green255\blue0;
\red255\green255\blue255;
";
private static string GetRTFColorFromColorRef(NativeMethods.COLORREF colorref)
{
return string.Concat("\\red", colorref.R.ToString("D"),
"\\green", colorref.G.ToString("D"),
"\\blue", colorref.B.ToString("D"), ";");
}
private static string GetColorTable()
{
var handle = NativeMethods.GetStdHandle((uint) StandardHandleId.Output);
var csbe = new NativeMethods.CONSOLE_SCREEN_BUFFER_INFO_EX
{
cbSize = Marshal.SizeOf<NativeMethods.CONSOLE_SCREEN_BUFFER_INFO_EX>()
};
if (NativeMethods.GetConsoleScreenBufferInfoEx(handle, ref csbe))
{
return GetRTFColorFromColorRef(csbe.Black) +
GetRTFColorFromColorRef(csbe.DarkBlue) +
GetRTFColorFromColorRef(csbe.DarkGreen) +
GetRTFColorFromColorRef(csbe.DarkCyan) +
GetRTFColorFromColorRef(csbe.DarkRed) +
GetRTFColorFromColorRef(csbe.DarkMagenta) +
GetRTFColorFromColorRef(csbe.DarkYellow) +
GetRTFColorFromColorRef(csbe.Gray) +
GetRTFColorFromColorRef(csbe.DarkGray) +
GetRTFColorFromColorRef(csbe.Blue) +
GetRTFColorFromColorRef(csbe.Green) +
GetRTFColorFromColorRef(csbe.Cyan) +
GetRTFColorFromColorRef(csbe.Red) +
GetRTFColorFromColorRef(csbe.Magenta) +
GetRTFColorFromColorRef(csbe.Yellow) +
GetRTFColorFromColorRef(csbe.White);
}
// A bit of a hack if the above failed - assume PowerShell's color scheme if the
// background color is Magenta, otherwise we assume the default scheme.
return _singleton._console.BackgroundColor == ConsoleColor.DarkMagenta
? PowerShellColorTable
: CmdColorTable;
}
private static void DumpScreenToClipboard(int top, int count)
{
var buffer = ReadBufferLines(top, count);
var bufferWidth = _singleton._console.BufferWidth;
var textBuffer = new StringBuilder(buffer.Length + count);
var rtfBuffer = new StringBuilder();
rtfBuffer.Append(@"{\rtf\ansi{\fonttbl{\f0 Consolas;}}");
var colorTable = GetColorTable();
rtfBuffer.AppendFormat(@"{{\colortbl;{0}}}{1}", colorTable, Environment.NewLine);
rtfBuffer.Append(@"\f0 \fs18 ");
var charInfo = buffer[0];
var fgColor = (int)charInfo.ForegroundColor;
var bgColor = (int)charInfo.BackgroundColor;
rtfBuffer.AppendFormat(@"{{\cf{0}\chshdng0\chcbpat{1} ", fgColor + 1, bgColor + 1);
for (int i = 0; i < count; i++)
{
var spaces = 0;
var rtfSpaces = 0;
for (int j = 0; j < bufferWidth; j++)
{
charInfo = buffer[i * bufferWidth + j];
if ((int)charInfo.ForegroundColor != fgColor || (int)charInfo.BackgroundColor != bgColor)
{
if (rtfSpaces > 0)
{
rtfBuffer.Append(' ', rtfSpaces);
rtfSpaces = 0;
}
fgColor = (int)charInfo.ForegroundColor;
bgColor = (int)charInfo.BackgroundColor;
rtfBuffer.AppendFormat(@"}}{{\cf{0}\chshdng0\chcbpat{1} ", fgColor + 1, bgColor + 1);
}
var c = (char)charInfo.UnicodeChar;
if (c == ' ')
{
// Trailing spaces are skipped, we'll add them back if we find a non-space
// before the end of line
++spaces;
++rtfSpaces;
}
else
{
if (spaces > 0)
{
textBuffer.Append(' ', spaces);
spaces = 0;
}
if (rtfSpaces > 0)
{
rtfBuffer.Append(' ', rtfSpaces);
rtfSpaces = 0;
}
textBuffer.Append(c);
switch (c)
{
case '\\': rtfBuffer.Append(@"\\"); break;
case '\t': rtfBuffer.Append(@"\tab"); break;
case '{': rtfBuffer.Append(@"\{"); break;
case '}': rtfBuffer.Append(@"\}"); break;
default: rtfBuffer.Append(c); break;
}
}
}
rtfBuffer.AppendFormat(@"\shading0 \cbpat{0} \par{1}", bgColor + 1, Environment.NewLine);
textBuffer.Append(Environment.NewLine);
}
rtfBuffer.Append("}}");
#if !CORECLR // TODO: break dependency on Window.Forms w/ p/invokes to clipboard directly, for now, just silently skip the copy.
var dataObject = new System.Windows.Forms.DataObject();
dataObject.SetData(System.Windows.Forms.DataFormats.Text, textBuffer.ToString());
dataObject.SetData(System.Windows.Forms.DataFormats.Rtf, rtfBuffer.ToString());
ExecuteOnSTAThread(() => System.Windows.Forms.Clipboard.SetDataObject(dataObject, copy: true));
#endif
}
}
}
#endif

View file

@ -1,242 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
private void RemoveEditsAfterUndo()
{
// If there is some sort of edit after an undo, forget
// any edit items that were undone.
int removeCount = _edits.Count - _undoEditIndex;
if (removeCount > 0)
{
_edits.RemoveRange(_undoEditIndex, removeCount);
if (_editGroupStart >= 0)
{
// Adjust the edit group start if we are started a group.
_editGroupStart -= removeCount;
}
}
}
private void SaveEditItem(EditItem editItem)
{
if (_statusIsErrorMessage)
{
// After an edit, clear the error message
ClearStatusMessage(render: true);
}
RemoveEditsAfterUndo();
_edits.Add(editItem);
_undoEditIndex = _edits.Count;
}
private void StartEditGroup()
{
if (_editGroupStart != -1)
{
// Nesting not supported.
throw new InvalidOperationException();
}
RemoveEditsAfterUndo();
_editGroupStart = _edits.Count;
}
private void EndEditGroup(Action<ConsoleKeyInfo?, object> instigator = null, object instigatorArg = null)
{
var groupEditCount = _edits.Count - _editGroupStart;
var groupedEditItems = _edits.GetRange(_editGroupStart, groupEditCount);
_edits.RemoveRange(_editGroupStart, groupEditCount);
SaveEditItem(GroupedEdit.Create(groupedEditItems, instigator, instigatorArg));
_editGroupStart = -1;
}
/// <summary>
/// Undo a previous edit.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void Undo(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton._undoEditIndex > 0)
{
if (_singleton._statusIsErrorMessage)
{
// After an edit, clear the error message
_singleton.ClearStatusMessage(render: false);
}
_singleton._edits[_singleton._undoEditIndex - 1].Undo();
_singleton._undoEditIndex--;
if (_singleton._options.EditMode == EditMode.Vi && _singleton._current >= _singleton._buffer.Length)
{
_singleton._current = Math.Max(0, _singleton._buffer.Length - 1);
}
_singleton.Render();
}
else
{
Ding();
}
}
/// <summary>
/// Undo an undo.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
public static void Redo(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton._undoEditIndex < _singleton._edits.Count)
{
_singleton._edits[_singleton._undoEditIndex].Redo();
_singleton._undoEditIndex++;
_singleton.Render();
}
else
{
Ding();
}
}
abstract class EditItem
{
public Action<ConsoleKeyInfo?, object> _instigator = null;
public object _instigatorArg = null;
public abstract void Undo();
public abstract void Redo();
}
[DebuggerDisplay("Insert '{_insertedCharacter}' ({_insertStartPosition})")]
class EditItemInsertChar : EditItem
{
// The character inserted is not needed for undo, only for redo
private char _insertedCharacter;
private int _insertStartPosition;
public static EditItem Create(char character, int position)
{
return new EditItemInsertChar
{
_insertedCharacter = character,
_insertStartPosition = position
};
}
public override void Undo()
{
Debug.Assert(_singleton._buffer[_insertStartPosition] == _insertedCharacter, "Character to undo is not what it should be");
_singleton._buffer.Remove(_insertStartPosition, 1);
_singleton._current = _insertStartPosition;
}
public override void Redo()
{
_singleton._buffer.Insert(_insertStartPosition, _insertedCharacter);
_singleton._current++;
}
}
[DebuggerDisplay("Insert '{_insertedString}' ({_insertStartPosition})")]
class EditItemInsertString : EditItem
{
// The string inserted tells us the length to delete on undo.
// The contents of the string are only needed for redo.
private string _insertedString;
private int _insertStartPosition;
public static EditItem Create(string str, int position)
{
return new EditItemInsertString
{
_insertedString = str,
_insertStartPosition = position
};
}
public override void Undo()
{
Debug.Assert(_singleton._buffer.ToString(_insertStartPosition, _insertedString.Length).Equals(_insertedString),
"Character to undo is not what it should be");
_singleton._buffer.Remove(_insertStartPosition, _insertedString.Length);
_singleton._current = _insertStartPosition;
}
public override void Redo()
{
_singleton._buffer.Insert(_insertStartPosition, _insertedString);
_singleton._current += _insertedString.Length;
}
}
[DebuggerDisplay("Delete '{_deletedString}' ({_deleteStartPosition})")]
class EditItemDelete : EditItem
{
private string _deletedString;
private int _deleteStartPosition;
public static EditItem Create(string str, int position, Action<ConsoleKeyInfo?, object> instigator = null, object instigatorArg = null)
{
return new EditItemDelete
{
_deletedString = str,
_deleteStartPosition = position,
_instigator = instigator,
_instigatorArg = instigatorArg
};
}
public override void Undo()
{
_singleton._buffer.Insert(_deleteStartPosition, _deletedString);
_singleton._current = _deleteStartPosition + _deletedString.Length;
}
public override void Redo()
{
_singleton._buffer.Remove(_deleteStartPosition, _deletedString.Length);
_singleton._current = _deleteStartPosition;
}
}
class GroupedEdit : EditItem
{
internal List<EditItem> _groupedEditItems;
public static EditItem Create(List<EditItem> groupedEditItems, Action<ConsoleKeyInfo?, object> instigator = null, object instigatorArg = null)
{
return new GroupedEdit
{
_groupedEditItems = groupedEditItems,
_instigator = instigator,
_instigatorArg = instigatorArg
};
}
public override void Undo()
{
for (int i = _groupedEditItems.Count - 1; i >= 0; i--)
{
_groupedEditItems[i].Undo();
}
}
public override void Redo()
{
foreach (var editItem in _groupedEditItems)
{
editItem.Redo();
}
}
}
}
}

View file

@ -1,70 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
private class GroupUndoHelper
{
public Action<ConsoleKeyInfo?, object> _instigator = null;
public object _instigatorArg = null;
public GroupUndoHelper()
{
_instigator = null;
_instigatorArg = null;
}
public void StartGroup(Action<ConsoleKeyInfo?, object> instigator, object instigatorArg)
{
_instigator = instigator;
_instigatorArg = instigatorArg;
_singleton.StartEditGroup();
}
public void Clear()
{
_instigator = null;
_instigatorArg = null;
}
public void EndGroup()
{
if (_singleton._editGroupStart >= 0)
{
_singleton.EndEditGroup(_instigator, _instigatorArg);
}
Clear();
}
}
private GroupUndoHelper _groupUndoHelper = new GroupUndoHelper();
/// <summary>
/// Undo all previous edits for line.
/// </summary>
public static void UndoAll(ConsoleKeyInfo? key = null, object arg = null)
{
if (_singleton._undoEditIndex > 0)
{
while (_singleton._undoEditIndex > 0)
{
_singleton._edits[_singleton._undoEditIndex - 1].Undo();
_singleton._undoEditIndex--;
}
_singleton.Render();
}
else
{
Ding();
}
}
}
}

View file

@ -1,111 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
private string _visualEditTemporaryFilename = null;
private Func<string, bool> _savedAddToHistoryHandler = null;
/// <summary>
/// Edit the command line in a text editor specified by $env:EDITOR or $env:VISUAL
/// </summary>
public static void ViEditVisually(ConsoleKeyInfo? key = null, object arg = null)
{
string editorOfChoice = GetPreferredEditor();
if (string.IsNullOrWhiteSpace(editorOfChoice))
{
Ding();
return;
}
_singleton._visualEditTemporaryFilename = GetTemporaryPowerShellFile();
using (FileStream fs = File.OpenWrite(_singleton._visualEditTemporaryFilename))
{
using (TextWriter tw = new StreamWriter(fs))
{
tw.Write(_singleton._buffer.ToString());
}
}
_singleton._savedAddToHistoryHandler = _singleton.Options.AddToHistoryHandler;
_singleton.Options.AddToHistoryHandler = ((string s) =>
{
return false;
});
_singleton._buffer.Clear();
_singleton._current = 0;
_singleton.Render();
_singleton._buffer.Append(editorOfChoice + " \'" + _singleton._visualEditTemporaryFilename + "\'");
AcceptLine();
}
private static string GetTemporaryPowerShellFile()
{
string filename;
do
{
filename = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".ps1");
} while (File.Exists(filename) || Directory.Exists(filename));
return filename;
}
private void ProcessViVisualEditing()
{
if (_visualEditTemporaryFilename == null)
{
return;
}
Options.AddToHistoryHandler = _savedAddToHistoryHandler;
_savedAddToHistoryHandler = null;
string editedCommand = null;
using (TextReader tr = File.OpenText(_visualEditTemporaryFilename))
{
editedCommand = tr.ReadToEnd();
}
File.Delete(_visualEditTemporaryFilename);
_visualEditTemporaryFilename = null;
if (!string.IsNullOrWhiteSpace(editedCommand))
{
while (editedCommand.Length > 0 && char.IsWhiteSpace(editedCommand[editedCommand.Length - 1]))
{
editedCommand = editedCommand.Substring(0, editedCommand.Length - 1);
}
editedCommand = editedCommand.Replace(Environment.NewLine, "\n");
_buffer.Clear();
_buffer.Append(editedCommand);
_current = _buffer.Length - 1;
Render();
//_queuedKeys.Enqueue(Keys.Enter);
}
}
private static string GetPreferredEditor()
{
string[] names = {"VISUAL", "EDITOR"};
foreach (string name in names)
{
string editor = Environment.GetEnvironmentVariable(name);
if (!string.IsNullOrWhiteSpace(editor))
{
return editor;
}
}
return null;
}
}
}

View file

@ -1,204 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System.Collections.Generic;
using System.Management.Automation.Language;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
private enum FindTokenMode
{
CurrentOrNext,
Next,
Previous,
}
static bool OffsetWithinToken(int offset, Token token)
{
return offset < token.Extent.EndOffset && offset >= token.Extent.StartOffset;
}
private Token FindNestedToken(int offset, IList<Token> tokens, FindTokenMode mode)
{
Token token = null;
bool foundNestedToken = false;
int i;
for (i = tokens.Count - 1; i >= 0; i--)
{
if (OffsetWithinToken(offset, tokens[i]))
{
token = tokens[i];
var strToken = token as StringExpandableToken;
if (strToken != null && strToken.NestedTokens != null)
{
var nestedToken = FindNestedToken(offset, strToken.NestedTokens, mode);
if (nestedToken != null)
{
token = nestedToken;
foundNestedToken = true;
}
}
break;
}
if (offset >= tokens[i].Extent.EndOffset)
{
break;
}
}
switch (mode)
{
case FindTokenMode.CurrentOrNext:
if (token == null && (i + 1) < tokens.Count)
{
token = tokens[i + 1];
}
break;
case FindTokenMode.Next:
if (!foundNestedToken)
{
// If there is no next token, return null (happens with nested
// tokens where there is no EOF/EOS token).
token = ((i + 1) < tokens.Count) ? tokens[i + 1] : null;
}
break;
case FindTokenMode.Previous:
if (token == null)
{
if (i >= 0)
{
token = tokens[i];
}
}
else if (offset == token.Extent.StartOffset)
{
token = i > 0 ? tokens[i - 1] : null;
}
break;
}
return token;
}
private Token FindToken(int current, FindTokenMode mode)
{
MaybeParseInput();
return FindNestedToken(current, _tokens, mode);
}
private bool InWord(int index, string wordDelimiters)
{
char c = _buffer[index];
return !char.IsWhiteSpace(c) && wordDelimiters.IndexOf(c) < 0;
}
/// <summary>
/// Find the end of the current/next word as defined by wordDelimiters and whitespace.
/// </summary>
private int FindForwardWordPoint(string wordDelimiters)
{
int i = _current;
if (i == _buffer.Length)
{
return i;
}
if (!InWord(i, wordDelimiters))
{
// Scan to end of current non-word region
while (i < _buffer.Length)
{
if (InWord(i, wordDelimiters))
{
break;
}
i += 1;
}
}
while (i < _buffer.Length)
{
if (!InWord(i, wordDelimiters))
{
break;
}
i += 1;
}
return i;
}
/// <summary>
/// Find the start of the next word.
/// </summary>
private int FindNextWordPoint(string wordDelimiters)
{
int i = _singleton._current;
if (i == _singleton._buffer.Length)
{
return i;
}
if (InWord(i, wordDelimiters))
{
// Scan to end of current word region
while (i < _singleton._buffer.Length)
{
if (!InWord(i, wordDelimiters))
{
break;
}
i += 1;
}
}
while (i < _singleton._buffer.Length)
{
if (InWord(i, wordDelimiters))
{
break;
}
i += 1;
}
return i;
}
/// <summary>
/// Find the beginning of the previous word.
/// </summary>
private int FindBackwardWordPoint(string wordDelimiters)
{
int i = _current - 1;
if (i < 0)
{
return 0;
}
if (!InWord(i, wordDelimiters))
{
// Scan backwards until we are at the end of the previous word.
while (i > 0)
{
if (InWord(i, wordDelimiters))
{
break;
}
i -= 1;
}
}
while (i > 0)
{
if (!InWord(i, wordDelimiters))
{
i += 1;
break;
}
i -= 1;
}
return i;
}
}
}

View file

@ -1,488 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System.Collections.Generic;
using System.Management.Automation.Language;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
private char _lastWordDelimiter = char.MinValue;
private bool _shouldAppend = false;
/// <summary>
/// Returns the position of the beginning of the next word as delimited by white space and delimiters.
/// </summary>
private int ViFindNextWordPoint(string wordDelimiters)
{
return ViFindNextWordPoint(_current, wordDelimiters);
}
/// <summary>
/// Returns the position of the beginning of the next word as delimited by white space and delimiters.
/// </summary>
private int ViFindNextWordPoint(int i, string wordDelimiters)
{
if (IsAtEndOfLine(i))
{
return i;
}
if (InWord(i, wordDelimiters))
{
return ViFindNextWordFromWord(i, wordDelimiters);
}
if (IsDelimiter(i, wordDelimiters))
{
return ViFindNextWordFromDelimiter(i, wordDelimiters);
}
return ViFindNextWordFromWhiteSpace(i, wordDelimiters);
}
private int ViFindNextWordFromWhiteSpace(int i, string wordDelimiters)
{
while (!IsAtEndOfLine(i) && IsWhiteSpace(i))
{
i++;
}
return i;
}
private int ViFindNextWordFromDelimiter(int i, string wordDelimiters)
{
while (!IsAtEndOfLine(i) && IsDelimiter(i, wordDelimiters))
{
i++;
}
if (IsAtEndOfLine(i))
{
if (IsDelimiter(i, wordDelimiters))
{
_shouldAppend = true;
return i + 1;
}
return i;
}
while (!IsAtEndOfLine(i) && IsWhiteSpace(i))
{
i++;
}
return i;
}
private bool IsAtEndOfLine(int i)
{
return i >= (_buffer.Length - 1);
}
private bool IsPastEndOfLine(int i)
{
return i > (_buffer.Length - 1);
}
private int ViFindNextWordFromWord(int i, string wordDelimiters)
{
while (!IsAtEndOfLine(i) && InWord(i, wordDelimiters))
{
i++;
}
if (IsAtEndOfLine(i) && InWord(i, wordDelimiters))
{
_shouldAppend = true;
return i + 1;
}
if (IsDelimiter(i, wordDelimiters))
{
_lastWordDelimiter = _buffer[i];
return i;
}
while (!IsAtEndOfLine(i) && IsWhiteSpace(i))
{
i++;
}
if (IsAtEndOfLine(i) && !InWord(i, wordDelimiters))
{
return i + 1;
}
_lastWordDelimiter = _buffer[i-1];
return i;
}
/// <summary>
/// Returns true of the character at the given position is white space.
/// </summary>
private bool IsWhiteSpace(int i)
{
return char.IsWhiteSpace(_buffer[i]);
}
/// <summary>
/// Returns the beginning of the current/next word as defined by wordDelimiters and whitespace.
/// </summary>
private int ViFindPreviousWordPoint(string wordDelimiters)
{
return ViFindPreviousWordPoint(_current, wordDelimiters);
}
/// <summary>
/// Returns the beginning of the current/next word as defined by wordDelimiters and whitespace.
/// </summary>
/// <param name="i">Current cursor location.</param>
/// <param name="wordDelimiters">Characters used to delimit words.</param>
/// <returns>Location of the beginning of the previous word.</returns>
private int ViFindPreviousWordPoint(int i, string wordDelimiters)
{
if (i == 0)
{
return i;
}
if (IsWhiteSpace(i))
{
return FindPreviousWordFromWhiteSpace(i, wordDelimiters);
}
else if (InWord(i, wordDelimiters))
{
return FindPreviousWordFromWord(i, wordDelimiters);
}
return FindPreviousWordFromDelimiter(i, wordDelimiters);
}
/// <summary>
/// Knowing that you're starting with a word, find the previous start of the next word.
/// </summary>
private int FindPreviousWordFromWord(int i, string wordDelimiters)
{
i--;
if (InWord(i, wordDelimiters))
{
while (i > 0 && InWord(i, wordDelimiters))
{
i--;
}
if (i == 0 && InWord(i, wordDelimiters))
{
return i;
}
return i + 1;
}
if (IsWhiteSpace(i))
{
while (i > 0 && IsWhiteSpace(i))
{
i--;
}
if (i == 0)
{
return i;
}
if (InWord(i, wordDelimiters) && InWord(i-1, wordDelimiters))
{
return FindPreviousWordFromWord(i, wordDelimiters);
}
if (IsDelimiter(i - 1, wordDelimiters))
{
FindPreviousWordFromDelimiter(i, wordDelimiters);
}
return i;
}
while (i > 0 && IsDelimiter(i, wordDelimiters))
{
i--;
}
if (i == 0 && IsDelimiter(i, wordDelimiters))
{
return i;
}
return i + 1;
}
/// <summary>
/// Returns true if the cursor is on a word delimiter
/// </summary>
private bool IsDelimiter(int i, string wordDelimiters)
{
return wordDelimiters.IndexOf(_buffer[i]) >= 0;
}
/// <summary>
/// Returns true if <paramref name="c"/> is in the set of <paramref name="wordDelimiters"/>.
/// </summary>
private bool IsDelimiter(char c, string wordDelimiters)
{
foreach (char delimiter in wordDelimiters)
{
if (c == delimiter)
{
return true;
}
}
return false;
}
/// <summary>
/// Returns the cursor position of the beginning of the previous word when starting on a delimiter
/// </summary>
private int FindPreviousWordFromDelimiter(int i, string wordDelimiters)
{
i--;
if (IsDelimiter(i, wordDelimiters))
{
while (i > 0 && IsDelimiter(i, wordDelimiters))
{
i--;
}
if (i == 0 && !IsDelimiter(i, wordDelimiters))
{
return i + 1;
}
if (!IsWhiteSpace(i))
{
return i + 1;
}
return i;
}
return ViFindPreviousWordPoint(i, wordDelimiters);
}
/// <summary>
/// Returns the cursor position of the beginning of the previous word when starting on white space
/// </summary>
private int FindPreviousWordFromWhiteSpace(int i, string wordDelimiters)
{
while (IsWhiteSpace(i) && i > 0)
{
i--;
}
int j = i - 1;
if (j < 0 || !InWord(i, wordDelimiters) || char.IsWhiteSpace(_buffer[j]))
{
return i;
}
return (ViFindPreviousWordPoint(i, wordDelimiters));
}
/// <summary>
/// Returns the cursor position of the previous word, ignoring all delimiters other what white space
/// </summary>
private int ViFindPreviousGlob()
{
int i = _current;
if (i == 0)
{
return 0;
}
i--;
return ViFindPreviousGlob(i);
}
/// <summary>
/// Returns the cursor position of the previous word from i, ignoring all delimiters other what white space
/// </summary>
private int ViFindPreviousGlob(int i)
{
if (i <= 0)
{
return 0;
}
if (!IsWhiteSpace(i))
{
while (i > 0 && !IsWhiteSpace(i))
{
i--;
}
if (!IsWhiteSpace(i))
{
return i;
}
return i + 1;
}
while (i > 0 && IsWhiteSpace(i))
{
i--;
}
if (i == 0)
{
return i;
}
return ViFindPreviousGlob(i);
}
/// <summary>
/// Finds the next work, using only white space as the word delimiter.
/// </summary>
private int ViFindNextGlob()
{
int i = _current;
return ViFindNextGlob(i);
}
private int ViFindNextGlob(int i)
{
if (i >= _buffer.Length)
{
return i;
}
while (!IsAtEndOfLine(i) && !IsWhiteSpace(i))
{
i++;
}
if (IsAtEndOfLine(i) && !IsWhiteSpace(i))
{
return i + 1;
}
while (!IsAtEndOfLine(i) && IsWhiteSpace(i))
{
i++;
}
if (IsAtEndOfLine(i) && IsWhiteSpace(i))
{
return i + 1;
}
return i;
}
/// <summary>
/// Finds the end of the current/next word as defined by whitespace.
/// </summary>
private int ViFindEndOfGlob()
{
return ViFindGlobEnd(_current);
}
/// <summary>
/// Find the end of the current/next word as defined by wordDelimiters and whitespace.
/// </summary>
private int ViFindNextWordEnd(string wordDelimiters)
{
int i = _current;
return ViFindNextWordEnd(i, wordDelimiters);
}
/// <summary>
/// Find the end of the current/next word as defined by wordDelimiters and whitespace.
/// </summary>
private int ViFindNextWordEnd(int i, string wordDelimiters)
{
if (IsAtEndOfLine(i))
{
return i;
}
if (IsDelimiter(i, wordDelimiters) && !IsDelimiter(i + 1, wordDelimiters))
{
i++;
if (IsAtEndOfLine(i))
{
return i;
}
}
else if (InWord(i, wordDelimiters) && !InWord(i + 1, wordDelimiters))
{
i++;
if (IsAtEndOfLine(i))
{
return i;
}
}
while (!IsAtEndOfLine(i) && IsWhiteSpace(i))
{
i++;
}
if (IsAtEndOfLine(i))
{
return i;
}
if (IsDelimiter(i, wordDelimiters))
{
while (!IsAtEndOfLine(i) && IsDelimiter(i, wordDelimiters))
{
i++;
}
if (!IsDelimiter(i, wordDelimiters))
{
return i - 1;
}
}
else
{
while (!IsAtEndOfLine(i) && InWord(i, wordDelimiters))
{
i++;
}
if (!InWord(i, wordDelimiters))
{
return i - 1;
}
}
return i;
}
/// <summary>
/// Return the last character in a white space defined word after skipping contiguous white space.
/// </summary>
private int ViFindGlobEnd(int i)
{
if (IsAtEndOfLine(i))
{
return i;
}
i++;
if (IsAtEndOfLine(i))
{
return i;
}
while (!IsAtEndOfLine(i) && IsWhiteSpace(i))
{
i++;
}
if (IsAtEndOfLine(i))
{
return i;
}
while (!IsAtEndOfLine(i) && !IsWhiteSpace(i))
{
i++;
}
if (IsWhiteSpace(i))
{
return i - 1;
}
return i;
}
private int ViFindEndOfPreviousGlob()
{
int i = _current;
return ViFindEndOfPreviousGlob(i);
}
private int ViFindEndOfPreviousGlob(int i)
{
if (IsWhiteSpace(i))
{
while (i > 0 && IsWhiteSpace(i))
{
i--;
}
return i;
}
while (i > 0 && !IsWhiteSpace(i))
{
i--;
}
return ViFindEndOfPreviousGlob(i);
}
}
}

View file

@ -1,338 +0,0 @@
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
private string _clipboard = string.Empty;
/// <summary>
/// Paste the clipboard after the cursor, moving the cursor to the end of the pasted text.
/// </summary>
public static void PasteAfter(ConsoleKeyInfo? key = null, object arg = null)
{
if (string.IsNullOrEmpty(_singleton._clipboard))
{
Ding();
return;
}
_singleton.PasteAfterImpl();
}
/// <summary>
/// Paste the clipboard before the cursor, moving the cursor to the end of the pasted text.
/// </summary>
public static void PasteBefore(ConsoleKeyInfo? key = null, object arg = null)
{
if (string.IsNullOrEmpty(_singleton._clipboard))
{
Ding();
return;
}
_singleton.PasteBeforeImpl();
}
private void PasteAfterImpl()
{
if (_current < _buffer.Length)
{
_current++;
}
Insert(_clipboard);
_current--;
Render();
}
private void PasteBeforeImpl()
{
Insert(_clipboard);
_current--;
Render();
}
private void SaveToClipboard(int startIndex, int length)
{
_clipboard = _buffer.ToString(startIndex, length);
}
/// <summary>
/// Yank the entire buffer.
/// </summary>
public static void ViYankLine(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.SaveToClipboard(0, _singleton._buffer.Length);
}
/// <summary>
/// Yank character(s) under and to the right of the cursor.
/// </summary>
public static void ViYankRight(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
int start = _singleton._current;
int length = 0;
while (numericArg-- > 0)
{
length++;
}
_singleton.SaveToClipboard(start, length);
}
/// <summary>
/// Yank character(s) to the left of the cursor.
/// </summary>
public static void ViYankLeft(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
int start = _singleton._current;
if (start == 0)
{
_singleton.SaveToClipboard(start, 1);
return;
}
int length = 0;
while (numericArg-- > 0)
{
if (start > 0)
{
start--;
length++;
}
}
_singleton.SaveToClipboard(start, length);
}
/// <summary>
/// Yank from the cursor to the end of the buffer.
/// </summary>
public static void ViYankToEndOfLine(ConsoleKeyInfo? key = null, object arg = null)
{
int start = _singleton._current;
int length = _singleton._buffer.Length - _singleton._current;
_singleton.SaveToClipboard(start, length);
}
/// <summary>
/// Yank the word(s) before the cursor.
/// </summary>
public static void ViYankPreviousWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
int start = _singleton._current;
while (numericArg-- > 0)
{
start = _singleton.ViFindPreviousWordPoint(start, _singleton.Options.WordDelimiters);
}
int length = _singleton._current - start;
if (length > 0)
{
_singleton.SaveToClipboard(start, length);
}
}
/// <summary>
/// Yank the word(s) after the cursor.
/// </summary>
public static void ViYankNextWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
int end = _singleton._current;
while (numericArg-- > 0)
{
end = _singleton.ViFindNextWordPoint(end, _singleton.Options.WordDelimiters);
}
int length = end - _singleton._current;
//if (_singleton.IsAtEndOfLine(end))
//{
// length++;
//}
if (length > 0)
{
_singleton.SaveToClipboard(_singleton._current, length);
}
}
/// <summary>
/// Yank from the cursor to the end of the word(s).
/// </summary>
public static void ViYankEndOfWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
int end = _singleton._current;
while (numericArg-- > 0)
{
end = _singleton.ViFindNextWordEnd(end, _singleton.Options.WordDelimiters);
}
int length = 1 + end - _singleton._current;
if (length > 0)
{
_singleton.SaveToClipboard(_singleton._current, length);
}
}
/// <summary>
/// Yank from the cursor to the end of the WORD(s).
/// </summary>
public static void ViYankEndOfGlob(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
int end = _singleton._current;
while (numericArg-- > 0)
{
end = _singleton.ViFindGlobEnd(end);
}
int length = 1 + end - _singleton._current;
if (length > 0)
{
_singleton.SaveToClipboard(_singleton._current, length);
}
}
/// <summary>
/// Yank from the beginning of the buffer to the cursor.
/// </summary>
public static void ViYankBeginningOfLine(ConsoleKeyInfo? key = null, object arg = null)
{
int length = _singleton._current;
if (length > 0)
{
_singleton.SaveToClipboard(0, length);
}
}
/// <summary>
/// Yank from the first non-whitespace character to the cursor.
/// </summary>
public static void ViYankToFirstChar(ConsoleKeyInfo? key = null, object arg = null)
{
int start = 0;
while (_singleton.IsWhiteSpace(start))
{
start++;
}
if (start == _singleton._current)
{
return;
}
int length = _singleton._current - start;
if (length > 0)
{
_singleton.SaveToClipboard(start, length);
}
}
/// <summary>
/// Yank to/from matching brace.
/// </summary>
public static void ViYankPercent(ConsoleKeyInfo? key = null, object arg = null)
{
int start = _singleton.ViFindBrace(_singleton._current);
if (_singleton._current < start)
{
_singleton.SaveToClipboard(_singleton._current, start - _singleton._current + 1);
}
else if (start < _singleton._current)
{
_singleton.SaveToClipboard(start, _singleton._current - start + 1);
}
else
{
Ding();
}
}
/// <summary>
/// Yank from beginning of the WORD(s) to cursor.
/// </summary>
public static void ViYankPreviousGlob(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
int start = _singleton._current;
while (numericArg-- > 0)
{
start = _singleton.ViFindPreviousGlob(start - 1);
}
if (start < _singleton._current)
{
_singleton.SaveToClipboard(start, _singleton._current - start);
}
else
{
Ding();
}
}
/// <summary>
/// Yank from cursor to the start of the next WORD(s).
/// </summary>
public static void ViYankNextGlob(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
int end = _singleton._current;
while (numericArg-- > 0)
{
end = _singleton.ViFindNextGlob(end);
}
_singleton.SaveToClipboard(_singleton._current, end - _singleton._current);
}
}
}

View file

@ -1,513 +0,0 @@
# Get-PSReadlineKeyHandler
## SYNOPSIS
Gets the key bindings for the PSReadline module.
## DESCRIPTION
Gets the key bindings for the PSReadline module.
If neither -Bound nor -Unbound is specified, returns all bound keys and unbound functions.
If -Bound is specified and -Unbound is not specified, only bound keys are returned.
If -Unbound is specified and -Bound is not specified, only unbound keys are returned.
If both -Bound and -Unbound are specified, returns all bound keys and unbound functions.
## PARAMETERS
### Bound [switch] = True
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Include functions that are bound.
### Unbound [switch] = True
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Include functions that are unbound.
## INPUTS
### None
You cannot pipe objects to Get-PSReadlineKeyHandler
## OUTPUTS
### Microsoft.PowerShell.KeyHandler
Returns one entry for each key binding (or chord) for bound functions and/or one entry for each unbound function
## RELATED LINKS
[about_PSReadline]()
# Get-PSReadlineOption
## SYNOPSIS
Returns the values for the options that can be configured.
## DESCRIPTION
Get-PSReadlineOption returns the current state of the settings that can be configured by Set-PSReadlineOption.
The object returned can be used to change PSReadline options.
This provides a slightly simpler way of setting syntax coloring options for multiple kinds of tokens.
## PARAMETERS
## INPUTS
### None
You cannot pipe objects to Get-PSReadlineOption
## OUTPUTS
###
## RELATED LINKS
[about_PSReadline]()
# Set-PSReadlineKeyHandler
## SYNOPSIS
Binds or rebinds keys to user defined or PSReadline provided key handlers.
## DESCRIPTION
This cmdlet is used to customize what happens when a particular key or sequence of keys is pressed while PSReadline is reading input.
With user defined key bindings, you can do nearly anything that is possible from a PowerShell script.
Typically you might just edit the command line in some novel way, but because the handlers are just PowerShell scripts, you can do interesting things like change directories, launch programs, etc.
## PARAMETERS
### Chord [String[]]
```powershell
[Parameter(
Mandatory = $true,
Position = 0)]
```
The key or sequence of keys to be bound to a Function or ScriptBlock.
A single binding is specified with a single string.
If the binding is a sequence of keys, the keys are separated with a comma, e.g. "Ctrl+X,Ctrl+X".
Note that this parameter accepts multiple strings.
Each string is a separate binding, not a sequence of keys for a single binding.
### ScriptBlock [ScriptBlock]
```powershell
[Parameter(
Mandatory = $true,
Position = 1,
ParameterSetName = 'Set 1')]
```
The ScriptBlock is called when the Chord is entered.
The ScriptBlock is passed one or sometimes two arguments.
The first argument is the key pressed (a ConsoleKeyInfo.) The second argument could be any object depending on the context.
### BriefDescription [String]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
A brief description of the key binding.
Used in the output of cmdlet Get-PSReadlineKeyHandler.
### Description [String]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
A more verbose description of the key binding.
Used in the output of the cmdlet Get-PSReadlineKeyHandler.
### Function [String]
```powershell
[Parameter(
Mandatory = $true,
Position = 1,
ParameterSetName = 'Set 2')]
```
The name of an existing key handler provided by PSReadline.
This parameter allows one to rebind existing key bindings or to bind a handler provided by PSReadline that is currently unbound.
Using the ScriptBlock parameter, one can achieve equivalent functionality by calling the method directly from the ScriptBlock.
This parameter is preferred though - it makes it easier to determine which functions are bound and unbound.
## INPUTS
### None
You cannot pipe objects to Set-PSReadlineKeyHandler
## OUTPUTS
###
## EXAMPLES
### -------------- Example 1 --------------
```powershell
PS C:\> Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
```
This command binds the up arrow key to the function HistorySearchBackward which will use the currently entered command line as the beginning of the search string when searching through history.
### -------------- Example 2 --------------
```powershell
PS C:\> Set-PSReadlineKeyHandler -Chord Shift+Ctrl+B -ScriptBlock {
[PSConsoleUtilities.PSConsoleReadLine]::RevertLine()
[PSConsoleUtilities.PSConsoleReadLine]::Insert('build')
>>> [PSConsoleUtilities.PSConsoleReadLine]::AcceptLine()
}
```
This example binds the key Ctrl+Shift+B to a script block that clears the line, inserts build, then accepts the line.
This example shows how a single key can be used to execute a command.
## RELATED LINKS
[about_PSReadline]()
# Set-PSReadlineOption
## SYNOPSIS
Customizes the behavior of command line editing in PSReadline.
## DESCRIPTION
The Set-PSReadlineOption cmdlet is used to customize the behavior of the PSReadline module when editing the command line.
## PARAMETERS
### EditMode [EditMode] = Windows
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the command line editing mode.
This will reset any key bindings set by Set-PSReadlineKeyHandler.
Valid values are:
-- Windows: Key bindings emulate PowerShell/cmd with some bindings emulating Visual Studio.
-- Emacs: Key bindings emulate Bash or Emacs.
### ContinuationPrompt [String] = >>>
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the string displayed at the beginning of the second and subsequent lines when multi-line input is being entered.
Defaults to '\>\>\> '.
The empty string is valid.
### ContinuationPromptForegroundColor [ConsoleColor]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the foreground color of the continuation prompt.
### ContinuationPromptBackgroundColor [ConsoleColor]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the background color of the continuation prompt.
### EmphasisForegroundColor [ConsoleColor] = Cyan
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the foreground color used for emphasis, e.g.
to highlight search text.
### EmphasisBackgroundColor [ConsoleColor]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the background color used for emphasis, e.g.
to highlight search text.
### ErrorForegroundColor [ConsoleColor] = Red
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the foreground color used for errors.
### ErrorBackgroundColor [ConsoleColor]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the background color used for errors.
### HistoryNoDuplicates [switch]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies that duplicate commands should not be added to PSReadline history.
### AddToHistoryHandler [Func[String, Boolean]]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies a ScriptBlock that can be used to control which commands get added to PSReadline history.
### ValidationHandler [Func[String, Object]]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies a ScriptBlock that is called from ValidateAndAcceptLine.
If a non-null object is returned or an exception is thrown, validation fails and the error is reported.
If the object returned/thrown has a Message property, it's value is used in the error message, and if there is an Offset property, the cursor is moved to that offset after reporting the error.
If there is no Message property, the ToString method is called to report the error.
### HistorySearchCursorMovesToEnd [switch]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
### MaximumHistoryCount [Int32] = 1024
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the maximum number of commands to save in PSReadline history.
Note that PSReadline history is separate from PowerShell history.
### MaximumKillRingCount [Int32] = 10
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the maximum number of items stored in the kill ring.
### ResetTokenColors [switch]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Restore the token colors to the default settings.
### ShowToolTips [switch]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
When displaying possible completions, show tooltips in the list of completions.
### ExtraPromptLineCount [Int32] = 0
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Use this option if your prompt spans more than one line and you want the extra lines to appear when PSReadline displays the prompt after showing some output, e.g.
when showing a list of completions.
### DingTone [Int32] = 1221
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
When BellStyle is set to Audible, specifies the tone of the beep.
### DingDuration [Int32] = 50ms
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
When BellStyle is set to Audible, specifies the duration of the beep.
### BellStyle [BellStyle] = Audible
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies how PSReadline should respond to various error and ambiguous conditions.
Valid values are:
-- Audible: a short beep
-- Visible: a brief flash is performed
-- None: no feedback
### CompletionQueryItems [Int32] = 100
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the maximum number of completion items that will be shown without prompting.
If the number of items to show is greater than this value, PSReadline will prompt y/n before displaying the completion items.
### WordDelimiters [string] = ;:,.[]{}()/\|^&*-=+
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the characters that delimit words for functions like ForwardWord or KillWord.
### HistorySearchCaseSensitive [switch]
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the searching history is case sensitive in functions like ReverseSearchHistory or HistorySearchBackward.
### HistorySaveStyle [HistorySaveStyle] = SaveIncrementally
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies how PSReadline should save history.
Valid values are:
-- SaveIncrementally: save history after each command is executed - and share across multiple instances of PowerShell
-- SaveAtExit: append history file when PowerShell exits
-- SaveNothing: don't use a history file
### HistorySavePath [String] = ~\AppData\Roaming\PSReadline\$($host.Name)_history.txt
```powershell
[Parameter(ParameterSetName = 'Set 1')]
```
Specifies the path to the history file.
### TokenKind [TokenClassification]
```powershell
[Parameter(
Mandatory = $true,
Position = 0,
ParameterSetName = 'Set 2')]
```
Specifies the kind of token when setting token coloring options with the -ForegroundColor and -BackgroundColor parameters.
### ForegroundColor [ConsoleColor]
```powershell
[Parameter(
Position = 1,
ParameterSetName = 'Set 2')]
```
Specifies the foreground color for the token kind specified by the parameter -TokenKind.
### BackgroundColor [ConsoleColor]
```powershell
[Parameter(
Position = 2,
ParameterSetName = 'Set 2')]
```
Specifies the background color for the token kind specified by the parameter -TokenKind.
## INPUTS
### None
You cannot pipe objects to Set-PSReadlineOption
## OUTPUTS
### None
This cmdlet does not generate any output.
## RELATED LINKS
[about_PSReadline]()

View file

@ -1,628 +0,0 @@
TOPIC
about_PSReadline
SHORT DESCRIPTION
PSReadline provides an improved command line editing experience in
the PowerShell console.
LONG DESCRIPTION
PSReadline provides a powerful command line editing experience for the
PowerShell console. It provides:
* Syntax coloring of the command line
* A visual indication of syntax errors
* A better multi-line experience (both editing and history)
* Customizable key bindings
* Cmd and Emacs modes
* Many configuration options
* Bash style completion (optional in Cmd mode, default in Emacs mode)
* Emacs yank/kill ring
* PowerShell token based "word" movement and kill
The following functions are available in the class [Microsoft.PowerShell.PSConsoleReadLine]:
Cursor movement
---------------
EndOfLine (Cmd: <End> Emacs: <End> or <Ctrl+E>)
If the input has multiple lines, move to the end of the current line,
or if already at the end of the line, move to the end of the input.
If the input has a single line, move to the end of the input.
BeginningOfLine (Cmd: <Home> Emacs: <Home> or <Ctrl+A>)
If the input has multiple lines, move to the start of the current line,
or if already at the start of the line, move to the start of the input.
If the input has a single line, move to the start of the input.
NextLine (Cmd: unbound Emacs: unbound)
Move the cursor to the next line if the input has multiple lines.
PreviousLine (Cmd: unbound Emacs: unbound)
Move the cursor to the previous line if the input has multiple lines.
ForwardChar (Cmd: <RightArrow> Emacs: <RightArrow> or <Ctrl+F>)
Move the cursor one character to the right. This may move the cursor to the next
line of multi-line input.
BackwardChar (Cmd: <LeftArrow> Emacs: <LeftArrow> or <Ctrl+B>)
Move the cursor one character to the left. This may move the cursor to the previous
line of multi-line input.
ForwardWord (Cmd: unbound Emacs: <Alt+F>)
Move the cursor forward to the end of the current word, or if between words,
to the end of the next word. Word delimiter characters can be set with:
Set-PSReadlineOption -WordDelimiters <string of delimiter characters>
NextWord (Cmd: <Ctrl+RightArrow> Emacs: unbound)
Move the cursor forward to the start of the next word. Word delimiter characters
can be set with:
Set-PSReadlineOption -WordDelimiters <string of delimiter characters>
BackwardWord (Cmd: <Ctrl+LeftArrow> Emacs: <Alt+B>)
Move the cursor back to the start of the current word, or if between words,
the start of the previous word. Word delimiter characters
can be set with:
Set-PSReadlineOption -WordDelimiters <string of delimiter characters>
ShellForwardWord (Cmd: unbound Emacs: unbound)
Like ForwardWord except word boundaries are defined by PowerShell token boundaries.
ShellNextWord (Cmd: unbound Emacs: unbound)
Like NextWord except word boundaries are defined by PowerShell token boundaries.
ShellBackwardWord (Cmd: unbound Emacs: unbound)
Like BackwardWord except word boundaries are defined by PowerShell token boundaries.
GotoBrace (Cmd: <Ctrl+}> Emacs: unbound)
Go to the matching parenthesis, curly brace, or square bracket.
AddLine (Cmd: <Shift-Enter> Emacs: <Shift-Enter>)
The continuation prompt is displayed on the next line and PSReadline waits for
keys to edit the current input. This is useful to enter multi-line input as
a single command even when a single line is complete input by itself.
Basic editing
-------------
CancelLine (Cmd: unbound Emacs: unbound)
Cancel all editing to the line, leave the line of input on the screen but
return from PSReadline without executing the input.
RevertLine (Cmd: <ESC> Emacs: <Alt+R>)
Reverts all of the input since the last input was accepted and executed.
This is equivalent to doing Undo until there is nothing left to undo.
BackwardDeleteChar (Cmd: <Backspace> Emacs: <Backspace> or <Ctrl+H>)
Delete the character before the cursor.
DeleteChar (Cmd: <Delete> Emacs: <Delete>)
Delete the character under the cursor.
DeleteCharOrExit (Cmd: unbound Emacs: <Ctrl+D>)
Like DeleteChar, unless the line is empty, in which case exit the process.
AcceptLine (Cmd: <Enter> Emacs: <Enter> or <Ctrl+M>)
Attempt to execute the current input. If the current input is incomplete (for
example there is a missing closing parenthesis, bracket, or quote, then the
continuation prompt is displayed on the next line and PSReadline waits for
keys to edit the current input.
AcceptAndGetNext (Cmd: unbound Emacs: <Ctrl+O>)
Like AcceptLine, but after the line completes, start editing the next line
from history.
ValidateAndAcceptLine (Cmd: unbound Emacs: unbound)
Like AcceptLine but performs additional validation including:
* Check for additional parse errors
* Validate command names are all found
* If using PowerShell V4 or greater, validate the parameters and arguments
If there are any errors, the error message is displayed and not accepted nor added
to the history unless you either correct the command line or execute AcceptLine or
ValidateAndAcceptLine again while the error message is displayed.
BackwardDeleteLine (Cmd: <Ctrl+Home> Emacs: unbound)
Delete the text from the start of the input to the cursor.
ForwardDeleteLine (Cmd: <Ctrl+End> Emacs: unbound)
Delete the text from the cursor to the end of the input.
SelectBackwardChar (Cmd: <Shift+LeftArrow> Emacs: <Shift+LeftArrow>)
Adjust the current selection to include the previous character.
SelectForwardChar (Cmd: <Shift+RightArrow> Emacs: <Shift+RightArrow>)
Adjust the current selection to include the next character.
SelectBackwardWord (Cmd: <Shift+Ctrl+LeftArrow> Emacs: <Alt+Shift+B>)
Adjust the current selection to include the previous word.
SelectForwardWord (Cmd: unbound Emacs: <Alt+Shift+F>)
Adjust the current selection to include the next word using ForwardWord.
SelectNextWord (Cmd: <Shift+Ctrl+RightArrow> Emacs: unbound)
Adjust the current selection to include the next word using NextWord.
SelectShellForwardWord (Cmd: unbound Emacs: unbound)
Adjust the current selection to include the next word using ShellForwardWord.
SelectShellNextWord (Cmd: unbound Emacs: unbound)
Adjust the current selection to include the next word using ShellNextWord.
SelectShellBackwardWord (Cmd: unbound Emacs: unbound)
Adjust the current selection to include the previous word using ShellBackwardWord.
SelectBackwardsLine (Cmd: <Shift+Home> Emacs: <Shift+Home>)
Adjust the current selection to include from the cursor to the start of the line.
SelectLine (Cmd: <Shift+End> Emacs: <Shift+End>)
Adjust the current selection to include from the cursor to the end of the line.
SelectAll (Cmd: <Ctrl+A> Emacs: unbound)
Select the entire line. Moves the cursor to the end of the line.
SelfInsert (Cmd: <a>, <b>, ... Emacs: <a>, <b>, ...)
Insert the key entered.
Redo (Cmd: <Ctrl+Y> Emacs: unbound)
Redo an insertion or deletion that was undone by Undo.
Undo (Cmd: <Ctrl+Z> Emacs: <Ctrl+_>)
Undo a previous insertion or deletion.
History
-------
ClearHistory (Cmd: Alt+F7 Emacs: unbound)
Clears history in PSReadline. This does not affect PowerShell history.
PreviousHistory (Cmd: <UpArrow> Emacs: <UpArrow> or <Ctrl+P>)
Replace the current input with the 'previous' item from PSReadline history.
NextHistory (Cmd: <DownArrow> Emacs: <DownArrow> or <Ctrl+N>)
Replace the current input with the 'next' item from PSReadline history.
ForwardSearchHistory (Cmd: <Ctrl+S> Emacs: <Ctrl+S>)
Search forward from the current history line interactively.
ReverseSearchHistory (Cmd: <Ctrl+R> Emacs: <Ctrl+R>)
Search backward from the current history line interactively.
HistorySearchBackward (Cmd: <F8> Emacs: unbound)
Replace the current input with the 'previous' item from PSReadline history
that matches the characters between the start and the input and the cursor.
HistorySearchForward (Cmd: <Shift+F8> Emacs: unbound)
Replace the current input with the 'next' item from PSReadline history
that matches the characters between the start and the input and the cursor.
BeginningOfHistory (Cmd: unbound Emacs: <Alt+<>)
Replace the current input with the last item from PSReadline history.
EndOfHistory (Cmd: unbound Emacs: <Alt+>>)
Replace the current input with the last item in PSReadline history, which
is the possibly empty input that was entered before any history commands.
Tab Completion
--------------
TabCompleteNext (Cmd: <Tab> Emacs: unbound)
Attempt to complete the text surrounding the cursor with the next
available completion.
TabCompletePrevious (Cmd: <Shift-Tab> Emacs: unbound)
Attempt to complete the text surrounding the cursor with the next
previous completion.
Complete (Cmd: unbound Emacs: <Tab>)
Attempt to perform completion on the text surrounding the cursor.
If there are multiple possible completions, the longest unambiguous
prefix is used for completion. If trying to complete the longest
unambiguous completion, a list of possible completions is displayed.
MenuComplete (Cmd: <Ctrl+Space> Emacs: <Ctrl+Space>)
Attempt to perform completion on the text surrounding the cursor.
If there are multiple possible completions, a list of possible
completions is displayed and you can select the correct completion
using the arrow keys or Tab/Shift+Tab. Escape and Ctrl+G cancel
the menu selection and reverts the line to the state before invoking
MenuComplete.
PossibleCompletions (Cmd: unbound Emacs: <Alt+Equals>)
Display the list of possible completions.
SetMark (Cmd: unbound Emacs: <Alt+Space>)
Mark the current location of the cursor for use in a subsequent editing command.
ExchangePointAndMark (Cmd: unbound Emacs: <Ctrl+X,Ctrl+X>)
The cursor is placed at the location of the mark and the mark is moved
to the location of the cursor.
Kill/Yank
---------
Kill and yank operate on a clipboard in the PSReadline module. There is a ring
buffer called the kill ring - killed text will be added to the kill ring up
and yank will copy text from the most recent kill. YankPop will cycle through
items in the kill ring. When the kill ring is full, new items will replace the
oldest items. A kill operation that is immediately preceded by another kill operation
will append the previous kill instead of adding a new item or replacing an item
in the kill ring. This is how you can cut a part of a line, say for example with multiple
KillWord operations, then yank them back elsewhere as a single yank.
KillLine (Cmd: unbound Emacs: <Ctrl+K>)
Clear the input from the cursor to the end of the line. The cleared text is placed
in the kill ring.
BackwardKillLine (Cmd: unbound Emacs: <Ctrl+U> or <Ctrl+X,Backspace>)
Clear the input from the start of the input to the cursor. The cleared text is placed
in the kill ring.
KillWord (Cmd: unbound Emacs: <Alt+D>)
Clear the input from the cursor to the end of the current word. If the cursor
is between words, the input is cleared from the cursor to the end of the next word.
The cleared text is placed in the kill ring.
BackwardKillWord (Cmd: unbound Emacs: <Alt+Backspace>)
Clear the input from the start of the current word to the cursor. If the cursor
is between words, the input is cleared from the start of the previous word to the
cursor. The cleared text is placed in the kill ring.
ShellKillWord (Cmd: unbound Emacs: unbound)
Like KillWord except word boundaries are defined by PowerShell token boundaries.
ShellBackwardKillWord (Cmd: unbound Emacs: unbound)
Like BackwardKillWord except word boundaries are defined by PowerShell token boundaries.
UnixWordRubout (Cmd: unbound Emacs: <Ctrl+W>)
Like BackwardKillWord except word boundaries are defined by whitespace.
KillRegion (Cmd: unbound Emacs: unbound)
Kill the text between the cursor and the mark.
Copy (Cmd: <Ctrl+Shift+C> Emacs: unbound)
Copy selected region to the system clipboard. If no region is selected, copy the whole line.
CopyOrCancelLine (Cmd: <Ctrl+C> Emacs: <Ctrl+C>)
Either copy selected text to the clipboard, or if no text is selected, cancel editing
the line with CancelLine.
Cut (Cmd: <Ctrl+X> Emacs: unbound)
Delete selected region placing deleted text in the system clipboard.
Yank (Cmd: unbound Emacs: <Ctrl+Y>)
Add the most recently killed text to the input.
YankPop (Cmd: unbound Emacs: <Alt+Y>)
If the previous operation was Yank or YankPop, replace the previously yanked
text with the next killed text from the kill ring.
ClearKillRing (Cmd: unbound Emacs: unbound)
The contents of the kill ring are cleared.
Paste (Cmd: <Ctrl+V> Emacs: unbound)
This is similar to Yank, but uses the system clipboard instead of the kill ring.
YankLastArg (Cmd: <Alt+.> Emacs: <Alt+.>, <Alt+_>)
Insert the last argument from the previous command in history. Repeated operations
will replace the last inserted argument with the last argument from the previous
command (so Alt+. Alt+. will insert the last argument of the second to last history
line.)
With an argument, the first time YankLastArg behaves like YankNthArg. A negative
argument on subsequent YankLastArg calls will change the direction while going
through history. For example, if you hit Alt+. one too many times, you can type
Alt+- Alt+. to reverse the direction.
Arguments are based on PowerShell tokens.
YankNthArg (Cmd: unbound Emacs: <Alt+Ctrl+Y>)
Insert the first argument (not the command name) of the previous command in history.
With an argument, insert the nth argument where 0 is typically the command. Negative
arguments start from the end.
Arguments are based on PowerShell tokens.
Miscellaneous
-------------
Abort (Cmd: unbound Emacs: <Ctrl+G>)
Abort the current action, e.g. stop interactive history search.
Does not cancel input like CancelLine.
CharacterSearch (Cmd: <F3> Emacs: <Ctrl+]>)
Read a key and search forwards for that character. With an argument, search
forwards for the nth occurrence of that argument. With a negative argument,
searches backwards.
CharacterSearchBackward (Cmd: <Shift+F3> Emacs: <Alt+Ctrl+]>)
Like CharacterSearch, but searches backwards. With a negative argument, searches
forwards.
ClearScreen (Cmd: <Ctrl+L> Emacs: <Ctrl+L>)
Clears the screen and displays the current prompt and input at the top of the screen.
DigitArgument (Cmd: unbound Emacs: <Alt+[0..9]>,,<Alt+->)
Used to pass numeric arguments to functions like CharacterSearch or YankNthArg.
Alt+- toggles the argument to be negative/non-negative. To enter 80 '*' characters,
you could type Alt+8 Alt+0 *.
CaptureScreen (Cmd: unbound Emacs: unbound)
Copies selected lines to the clipboard in both text and rtf formats. Use up/down
arrow keys to the first line to select, then Shift+UpArrow/Shift+DownArrow to select
multiple lines. After selecting, press Enter to copy the text. Escape/Ctrl+C/Ctrl+G
will cancel so nothing is copied to the clipboard.
InvokePrompt (Cmd: unbound Emacs: unbound)
Erases the current prompt and calls the prompt function to redisplay
the prompt. Useful for custom key handlers that change state, e.g.
change the current directory.
WhatIsKey (Cmd: <Alt+?> Emacs: <Alt+?>)
Read a key or chord and display the key binding.
ShowKeyBindings (Cmd: <Ctrl+Alt+?> Emacs: <Ctrl+Alt+?>)
Show all of the currently bound keys.
ScrollDisplayUp (Cmd: <PageUp> Emacs: <PageUp>)
Scroll the display up one screen.
ScrollDisplayUpLine (Cmd: <Ctrl+PageUp> Emacs: <Ctrl+PageUp>)
Scroll the display up one line.
ScrollDisplayDown (Cmd: <PageDown> Emacs: <PageDown>)
Scroll the display down one screen.
ScrollDisplayDownLine (Cmd: <Ctrl+PageDown> Emacs: <Ctrl+PageDown>)
Scroll the display down one line.
ScrollDisplayTop (Cmd: unbound Emacs: <Ctrl+Home>)
Scroll the display to the top.
ScrollDisplayToCursor (Cmd: unbound Emacs: <Ctrl+End>)
Scroll the display to the cursor.
Custom Key Bindings
-------------------
PSReadline supports custom key bindings using the cmdlet Set-PSReadlineKeyHandler. Most
custom key bindings will call one of the above functions, for example:
Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
You can bind a ScriptBlock to a key. The ScriptBlock can do pretty much anything you want.
Some useful examples include:
* edit the command line
* opening a new window (e.g. help)
* change directories without changing the command line
The ScriptBlock is passed two arguments:
* $key - A [ConsoleKeyInfo] that is the key that triggered the custom binding. If you bind
the same ScriptBlock to multiple keys and need to perform different actions depending
on the key, you can check $key. Many custom bindings ignore this argument.
* $arg - An arbitrary argument. Most often, this would be an integer argument that the user
passes from the key bindings DigitArgument. If your binding doesn't accept arguments,
it's reasonable to ignore this argument.
Let's take a look at an example that adds a command line to history without executing it. This is
useful when you realize you forgot to do something, but don't want to re-enter the command line
you've already entered.
Set-PSReadlineKeyHandler -Key Alt+w `
-BriefDescription SaveInHistory `
-LongDescription "Save current line in history but do not execute" `
-ScriptBlock {
param($key, $arg) # The arguments are ignored in this example
# We need the command line, GetBufferState gives us that (with the cursor position)
$line = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
# AddToHistory saves the line in history, but does not execute the line.
[Microsoft.PowerShell.PSConsoleReadLine]::AddToHistory($line)
# RevertLine is like pressing Escape.
[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
}
You can see many more examples in the file SamplePSReadlineProfile.ps1 which is installed in the
PSReadline module folder.
Most key bindings will want to take advantage of some helper functions for editing the command
line those APIs are documented in the next section.
Custom Key Binding Support APIs
-------------------------------
The following functions are public in Microsoft.PowerShell.PSConsoleReadline, but cannot be directly
bound to a key. Most are useful in custom key bindings.
void AddToHistory(string command)
Add a command line to history without executing it.
void ClearKillRing()
Clear the kill ring. This is mostly used for testing.
void Delete(int start, int length)
Delete length characters from start. This operation supports undo/redo.
void Ding()
Perform the Ding action based on the users preference.
void GetBufferState([ref] string input, [ref] int cursor)
void GetBufferState([ref] Ast ast, [ref] Token[] tokens, [ref] ParseError[] parseErrors, [ref] int cursor)
These two functions retrieve useful information about the current state of
the input buffer. The first is more commonly used for simple cases. The
second is used if your binding is doing something more advanced with the Ast.
IEnumerable[Microsoft.PowerShell.KeyHandler] GetKeyHandlers(bool includeBound, bool includeUnbound)
This function is used by Get-PSReadlineKeyHandler and probably isn't useful in a custom
key binding.
Microsoft.PowerShell.PSConsoleReadlineOptions GetOptions()
This function is used by Get-PSReadlineOption and probably isn't too useful in a custom
key binding.
void GetSelectionState([ref] int start, [ref] int length)
If there is no selection on the command line, -1 will be returned in both start and length.
If there is a selection on the command line, the start and length of the selection are returned.
void Insert(char c)
void Insert(string s)
Insert a character or string at the cursor. This operation supports undo/redo.
string ReadLine(runspace remoteRunspace, System.Management.Automation.EngineIntrinsics engineIntrinsics)
This is the main entry point to PSReadline. It does not support recursion, so is not useful
in a custom key binding.
void RemoveKeyHandler(string[] key)
This function is used by Remove-PSReadlineKeyHandler and probably isn't too useful in a
custom key binding.
void Replace(int start, int length, string replacement)
Replace some of the input. This operation supports undo/redo.
This is preferred over Delete followed by Insert because it is treated as a single action
for undo.
void SetCursorPosition(int cursor)
Move the cursor to the given offset. Cursor movement is not tracked for undo.
void SetOptions(Microsoft.PowerShell.SetPSReadlineOption options)
This function is a helper method used by the cmdlet Set-PSReadlineOption, but might be
useful to a custom key binding that wants to temporarily change a setting.
bool TryGetArgAsInt(System.Object arg, [ref] int numericArg, int defaultNumericArg)
This helper method is used for custom bindings that honor DigitArgument. A typical call
looks like:
[int]$numericArg = 0
[Microsoft.PowerShell.PSConsoleReadLine]::TryGetArgAsInt($arg, [ref]$numericArg, 1)
POWERSHELL COMPATIBILITY
PSReadline requires PowerShell version 3 or greater and the console host. It
will not work in the ISE.
FEEDBACK
https://github.com/lzybkr/PSReadline
CONTRIBUTING TO PSREADLINE
Feel free to submit a pull request or submit feedback on the github page.
SEE ALSO
PSReadline is heavily influenced by the GNU Readline library:
http://tiswww.case.edu/php/chet/readline/rltop.html

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.PowerShell.3.ReferenceAssemblies" version="1.0.0" targetFramework="net40-Client" />
</packages>

View file

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<Import Project="..\..\PowerShell.Common.props" />
<ItemGroup>
<PackageReference Include="PackageManagement" Version="1.1.7.0" />
<PackageReference Include="PowerShellGet" Version="1.6.0" />
<PackageReference Include="PSReadLine" Version="2.0.0-beta1" />
<PackageReference Include="Microsoft.PowerShell.Archive" Version="1.1.0.0" />
</ItemGroup>
</Project>

View file

@ -1,17 +0,0 @@
@{
RootModule = 'PSReadLine.psm1'
NestedModules = @("Microsoft.PowerShell.PSReadLine.dll")
ModuleVersion = '1.2'
GUID = '5714753b-2afd-4492-a5fd-01d9e2cff8b5'
Author = 'Microsoft Corporation'
CompanyName = 'Microsoft Corporation'
Copyright = 'Copyright (c) Microsoft Corporation. All rights reserved.'
Description = 'Great command line editing in the PowerShell console host'
PowerShellVersion = '3.0'
DotNetFrameworkVersion = '4.0'
CLRVersion = '4.0'
FunctionsToExport = 'PSConsoleHostReadline'
CmdletsToExport = 'Get-PSReadlineKeyHandler','Set-PSReadlineKeyHandler','Remove-PSReadlineKeyHandler',
'Get-PSReadlineOption','Set-PSReadlineOption'
HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855966'
}

View file

@ -1,5 +0,0 @@
function PSConsoleHostReadline
{
Microsoft.PowerShell.Core\Set-StrictMode -Off
[Microsoft.PowerShell.PSConsoleReadLine]::ReadLine($host.Runspace, $ExecutionContext)
}

View file

@ -682,7 +682,6 @@ namespace NativeMsh
"Microsoft.PowerShell.ConsoleHost",
"Microsoft.PowerShell.CoreCLR.Eventing",
"Microsoft.PowerShell.LocalAccounts",
"Microsoft.PowerShell.PSReadLine",
"Microsoft.PowerShell.SDK",
"Microsoft.PowerShell.Security",
"Microsoft.VisualBasic",

View file

@ -24,7 +24,6 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.PowerShell.SDK\Microsoft.PowerShell.SDK.csproj" />
<ProjectReference Include="..\Microsoft.PowerShell.PSReadLine\Microsoft.PowerShell.PSReadLine.csproj" />
</ItemGroup>
<ItemGroup>

View file

@ -27,7 +27,6 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.PowerShell.SDK\Microsoft.PowerShell.SDK.csproj" />
<ProjectReference Include="..\Microsoft.PowerShell.PSReadLine\Microsoft.PowerShell.PSReadLine.csproj" />
<ProjectReference Include="..\Microsoft.PowerShell.Commands.Diagnostics\Microsoft.PowerShell.Commands.Diagnostics.csproj" />
<ProjectReference Include="..\Microsoft.Management.Infrastructure.CimCmdlets\Microsoft.Management.Infrastructure.CimCmdlets.csproj" />
<ProjectReference Include="..\Microsoft.WSMan.Management\Microsoft.WSMan.Management.csproj" />

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

View file

@ -1,35 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("TestPSReadLine")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TestPSReadLine")]
[assembly: AssemblyCopyright("Copyright (c) 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("2892ed9f-6820-48a0-819b-0452c3b5401b")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\Test.Common.props"/>
<PropertyGroup>
<Description>PSReadLine basic tests</Description>
<AssemblyName>TestPSReadLine</AssemblyName>
<OutputType>Exe</OutputType>
<RuntimeIdentifiers>win7-x86;win7-x64;osx.10.12-x64;linux-x64</RuntimeIdentifiers>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.PowerShell.PSReadLine\Microsoft.PowerShell.PSReadLine.csproj" />
</ItemGroup>
</Project>

View file

@ -1,80 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell;
namespace TestPSReadLine
{
class Program
{
static void CauseCrash(ConsoleKeyInfo? key = null, object arg = null)
{
throw new Exception("intentional crash for test purposes");
}
[STAThread]
static void Main()
{
//Box(new List<string> {"abc", " def", "this is something coo"});
var iss = InitialSessionState.CreateDefault2();
var rs = RunspaceFactory.CreateRunspace(iss);
rs.Open();
Runspace.DefaultRunspace = rs;
PSConsoleReadLine.SetOptions(new SetPSReadlineOption
{
EditMode = EditMode.Emacs,
HistoryNoDuplicates = true,
});
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+LeftArrow"}, PSConsoleReadLine.ShellBackwardWord, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+RightArrow"}, PSConsoleReadLine.ShellNextWord, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F4"}, PSConsoleReadLine.HistorySearchBackward, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F5"}, PSConsoleReadLine.HistorySearchForward, "", "");
//PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+E"}, PSConsoleReadLine.EnableDemoMode, "", "");
//PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+D"}, PSConsoleReadLine.DisableDemoMode, "", "");
// PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+C"}, PSConsoleReadLine.CaptureScreen, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+P"}, PSConsoleReadLine.InvokePrompt, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+X"}, CauseCrash, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F6"}, PSConsoleReadLine.PreviousLine, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F7"}, PSConsoleReadLine.NextLine, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F2"}, PSConsoleReadLine.ValidateAndAcceptLine, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Enter"}, PSConsoleReadLine.AcceptLine, "", "");
EngineIntrinsics executionContext;
using (var ps = PowerShell.Create(RunspaceMode.CurrentRunspace))
{
executionContext =
ps.AddScript("$ExecutionContext").Invoke<EngineIntrinsics>().FirstOrDefault();
// 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 host stops responding, run it once, then comment it out again.
//ps.Commands.Clear();
//ps.AddCommand("Get-Command").Invoke();
}
while (true)
{
Console.Write("TestHostPS> ");
var line = PSConsoleReadLine.ReadLine(null, executionContext);
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});
}
}
}
}

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.PowerShell.3.ReferenceAssemblies" version="1.0.0" targetFramework="net45" />
</packages>

View file

@ -10,7 +10,7 @@ Describe "PSReadLine" -tags "CI" {
Import-Module PSReadLine
$module = Get-Module PSReadLine
$module.Name | Should Be "PSReadLine"
$module.Version | Should Be "1.2"
$module.Version | Should Be "2.0.0"
}
It "Should use Emacs Bindings on Linux and macOS" -skip:$IsWindows {

View file

@ -394,7 +394,6 @@ function Expand-ZipArchive([string] $Path, [string] $DestinationPath)
Microsoft.WSMan.Management 3.93 4.45 Branch:3.93 Sequence:4.45
Microsoft.WSMan.Runtime 0 0 Branch: 0 Sequence: 0
Microsoft.PowerShell.Commands.Diagnostics 44.96 49.93 Branch:44.96 Sequence:49.93
Microsoft.PowerShell.PSReadLine 7.12 9.94 Branch:7.12 Sequence:9.94
Microsoft.PowerShell.PackageManagement 59.77 62.04 Branch:59.77 Sequence:62.04
Microsoft.PackageManagement 41.73 44.47 Branch:41.73 Sequence:44.47
Microsoft.Management.Infrastructure.CimCmdlets 13.20 17.01 Branch:13.20 Sequence:17.01
@ -451,7 +450,6 @@ function Get-CodeCoverage
Microsoft.PowerShell.CoreCLR.AssemblyLoadContext 53.66 0 95.31 0
Microsoft.PowerShell.CoreCLR.Eventing 28.70 0 36.23 0
Microsoft.PowerShell.PackageManagement 59.77 0 62.04 0
Microsoft.PowerShell.PSReadLine 7.12 0 9.94 0
Microsoft.PowerShell.Security 15.17 0 18.16 0
Microsoft.WSMan.Management 3.93 0 4.45 0
Microsoft.WSMan.Runtime 0 0 0 0
@ -477,7 +475,6 @@ function Get-CodeCoverage
Microsoft.PowerShell.CoreCLR.AssemblyLoadContext 53.66 0 95.31 0
Microsoft.PowerShell.CoreCLR.Eventing 28.70 0 36.23 0
Microsoft.PowerShell.PackageManagement 59.77 0 62.04 0
Microsoft.PowerShell.PSReadLine 7.12 0 9.94 0
Microsoft.PowerShell.Security 15.17 0 18.16 0
Microsoft.WSMan.Management 3.93 0 4.45 0
Microsoft.WSMan.Runtime 0 0 0 0