Last active
June 1, 2019 19:09
-
-
Save scrthq/6b2dfc7efc459399c872d23a663d7914 to your computer and use it in GitHub Desktop.
PowerShell Profile components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$global:PSProfileConfig = @{ | |
_internal = @{ | |
ProfileLoadStart = Get-Date | |
} | |
Settings = @{ | |
Prompt = 'Slim' | |
PSVersionStringLength = 3 | |
} | |
Variables = @{ | |
Environment = @{ | |
USERPROFILE = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::UserProfile) | |
} | |
Global = @{ | |
CodeProfile = $PSScriptRoot | |
PathAliasDirectorySeparator = [System.IO.Path]::DirectorySeparatorChar | |
AltPathAliasDirectorySeparator = [char]0xe0b1 | |
} | |
} | |
GitPaths = @{ | |
Work = 'WorkGit' | |
Personal = 'ScrtGit' | |
Other = 'E:\Git' | |
} | |
PathAliases = @( | |
@{ | |
Alias = '~' | |
Path = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::UserProfile) | |
} | |
) | |
GistsToInvoke = @( | |
@{ | |
Id = '6b2dfc7efc459399c872d23a663d7914' | |
Metadata = @{ | |
Description = 'PowerShell Profile Components' | |
} | |
} | |
) | |
ModulesToImport = @( | |
'PSChef' | |
'PSToolbelt' | |
'MyConfig' | |
) | |
} | |
$log = { | |
Param( | |
$Message, | |
$Section = "Info", | |
$Action = "Log", | |
$Start = $(if ($global:PSProfileConfig._internal.ProfileLoadStart){$global:PSProfileConfig._internal.ProfileLoadStart}else{Get-Date}) | |
) | |
$now = Get-Date | |
$ls = if ($null -eq $script:LastProfileCommandTime) { | |
$now - $Start | |
} | |
else { | |
$now - $script:LastProfileCommandTime | |
} | |
$ts = $now - $Start | |
Write-Host -ForegroundColor Cyan ("[L+{0:00}.{1:000}s] [T+{2:00}.{3:000}s] [{4}] [{5}] {6}" -f ([Math]::Floor($ls.TotalSeconds)),$ls.Milliseconds,([Math]::Floor($ts.TotalSeconds)),$ts.Milliseconds,"$Section".PadRight(10,'.'),"$Action".PadRight(9,'.'),$Message) | |
$script:LastProfileCommandTime = Get-Date | |
} | |
function Get-Gist { | |
[CmdletBinding()] | |
Param ( | |
[parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName,Position = 0)] | |
[String] | |
$Id, | |
[parameter(ValueFromPipelineByPropertyName)] | |
[Alias('Files')] | |
[String[]] | |
$File, | |
[parameter(ValueFromPipelineByPropertyName)] | |
[String] | |
$Sha, | |
[parameter(ValueFromPipelineByPropertyName,ValueFromRemainingArguments)] | |
[Object] | |
$Metadata, | |
[parameter()] | |
[Switch] | |
$Invoke | |
) | |
Process { | |
$Uri = [System.Collections.Generic.List[string]]@( | |
'https://api.github.com' | |
'/gists/' | |
$PSBoundParameters['Id'] | |
) | |
if ($PSBoundParameters.ContainsKey('Sha')) { | |
$Uri.Add("/$($PSBoundParameters['Sha'])") | |
Write-Verbose "[$($PSBoundParameters['Id'])] Getting gist info @ SHA '$($PSBoundParameters['Sha'])'" | |
} | |
else { | |
Write-Verbose "[$($PSBoundParameters['Id'])] Getting gist info" | |
} | |
$gistInfo = Invoke-RestMethod -Uri ([Uri](-join $Uri)) -Verbose:$false | |
$fileNames = if ($PSBoundParameters.ContainsKey('File')) { | |
$PSBoundParameters['File'] | |
} | |
else { | |
$gistInfo.files.PSObject.Properties.Name | |
} | |
foreach ($fileName in $fileNames) { | |
Write-Verbose "[$fileName] Getting gist file content" | |
$fileInfo = $gistInfo.files.$fileName | |
$content = if ($fileInfo.truncated) { | |
(Invoke-WebRequest -Uri ([Uri]$fileInfo.raw_url)).Content | |
} | |
else { | |
$fileInfo.content | |
} | |
$lines = ($content -split "`n").Count | |
if ($Invoke) { | |
Write-Verbose "[$fileName] Parsing gist file content ($lines lines)" | |
$noScopePattern = '^function\s+(?<Name>[\w+_-]{1,})\s+\{' | |
$globalScopePattern = '^function\s+global\:' | |
$noScope = [RegEx]::Matches($content, $noScopePattern, "Multiline, IgnoreCase") | |
$globalScope = [RegEx]::Matches($content,$globalScopePattern,"Multiline, IgnoreCase") | |
if ($noScope.Count -ge $globalScope.Count) { | |
foreach ($match in $noScope) { | |
$fullValue = ($match.Groups | Where-Object { $_.Name -eq 0 }).Value | |
$funcName = ($match.Groups | Where-Object { $_.Name -eq 'Name' }).Value | |
Write-Verbose "[$fileName::$funcName] Updating function to global scope to ensure it imports correctly." | |
$content = $content.Replace($fullValue, "function global:$funcName {") | |
} | |
} | |
Write-Verbose "[$fileName] Invoking gist file content" | |
$ExecutionContext.InvokeCommand.InvokeScript( | |
$false, | |
([scriptblock]::Create($content)), | |
$null, | |
$null | |
) | |
} | |
[PSCustomObject]@{ | |
File = $fileName | |
Sha = $Sha | |
Count = $lines | |
Content = $content -join "`n" | |
} | |
} | |
} | |
} | |
Write-Host -ForegroundColor Yellow " | |
[LastTime.] [TotalTime] [Section...] [Action...] Log Message... | |
----------- ----------- ------------ ----------- ---------------------------------------------------------------------" | |
if (-not (Test-Path $profile.CurrentUserAllHosts)) { | |
&$log "Creating CurrentUserAllHosts file" "Profile" "Maint" | |
New-Item $profile.CurrentUserAllHosts -Force | |
} | |
#region: Apply the $global:PSProfileConfig | |
foreach ($var in $global:PSProfileConfig.Variables.Environment.Keys) { | |
&$log "`$env:$var = '$($global:PSProfileConfig.Variables.Environment[$var])'" "Variable" "Set" | |
Set-Item "Env:\$var" -Value $global:PSProfileConfig.Variables.Environment[$var] -Force | |
} | |
foreach ($var in $global:PSProfileConfig.Variables.Global.Keys) { | |
&$log "`$global:$var = '$($global:PSProfileConfig.Variables.Global[$var])'" "Variable" "Set" | |
Set-Variable -Name $var -Value $global:PSProfileConfig.Variables.Global[$var] -Scope Global -Force | |
} | |
$aliasMapJson = @{ } | |
foreach ($category in $global:PSProfileConfig.GitPaths.Keys) { | |
$aliasIcon = switch ($category) { | |
Work { | |
'$' | |
} | |
Personal { | |
'@' | |
} | |
default { | |
'#' | |
} | |
} | |
if ($global:PSProfileConfig.GitPaths[$category] -notmatch [RegEx]::Escape(([System.IO.Path]::DirectorySeparatorChar))) { | |
$paired = $false | |
$env:USERPROFILE,$PWD.Path,$PWD.Drive.Root | ForEach-Object { | |
if (-not $paired) { | |
$gitPath = Join-Path $_ $global:PSProfileConfig.GitPaths[$category] | |
if (Test-Path $gitPath) { | |
$paired = $true | |
} | |
} | |
} | |
} | |
else { | |
$gitPath = $global:PSProfileConfig.GitPaths[$category] | |
} | |
&$log "'$($aliasIcon)git' = '$($gitPath)'" "PathAlias" "Set" | |
$aliasMapJson["$($aliasIcon)git"] = $gitPath | |
} | |
foreach ($alias in $global:PSProfileConfig.PathAliases) { | |
&$log "'$($alias['Alias'])' = '$($alias['Path'])'" "PathAlias" "Set" | |
$aliasMapJson[$alias['Alias']] = $alias['Path'] | |
} | |
$global:PSProfileConfig['_internal']['PathAliasMap'] = $aliasMapJson | |
$global:PSProfileConfig['_internal']['GitPathMap'] = @{ CodeProfile = $global:CodeProfile } | |
$global:PSProfileConfig['_internal']['PSBuildPathMap'] = @{} | |
foreach ($key in $global:PSProfileConfig.GitPaths.Keys) { | |
$fullPath = if (Test-Path ($global:PSProfileConfig.GitPaths[$key])) { | |
$global:PSProfileConfig.GitPaths[$key] | |
} | |
elseif (Test-Path (Join-Path "~" $global:PSProfileConfig.GitPaths[$key])) { | |
Join-Path "~" $global:PSProfileConfig.GitPaths[$key] | |
} | |
elseif (Test-Path (Join-Path $PWD.Drive.Root $global:PSProfileConfig.GitPaths[$key])) { | |
Join-Path $PWD.Drive.Root $global:PSProfileConfig.GitPaths[$key] | |
} | |
else { | |
"???<$($global:PSProfileConfig.GitPaths[$key])>" | |
} | |
&$log "$key[$fullPath]" "GitRepos" "Discover" | |
$g = 0 | |
$b = 0 | |
if ($fullPath -notmatch '^\?\?\?' -and (Test-Path $fullPath)) { | |
Get-ChildItem $fullPath -Recurse -Filter '.git' -Directory -Force | ForEach-Object { | |
$global:PSProfileConfig['_internal']['GitPathMap'][$_.Parent.BaseName] = $_.Parent.FullName | |
$g++ | |
if (Test-Path (Join-Path $_.Parent.FullName "build.ps1")) { | |
$global:PSProfileConfig['_internal']['PSBuildPathMap'][$_.Parent.BaseName] = $_.Parent.FullName | |
$b++ | |
} | |
} | |
} | |
&$log "$key[$fullPath] :: $g git | $b build" "GitRepos" "Report" | |
} | |
#endregion: Apply the $global:PSProfileConfig | |
if (-not $env:DemoInProgress) { | |
$global:PSProfileConfig.ModulesToImport | ForEach-Object { | |
&$log $_ "Module" "Import" | |
Import-Module $_ -ErrorAction SilentlyContinue | |
} | |
if ($global:PSProfileConfig.Settings.Prompt) { | |
Switch-Prompt -Prompt $global:PSProfileConfig.Settings.Prompt | |
} | |
} | |
else { | |
demo | |
} | |
Write-Host ("Loading personal profile alone took {0}ms." -f ([Math]::Round(((Get-Date) - $global:PSProfileConfig._internal.ProfileLoadStart).TotalMilliseconds,0))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Start-Demo { | |
param( | |
[parameter(Mandatory = $false, Position = 0)] | |
[string] | |
$File = ".\demo.txt", | |
[parameter(Mandatory = $false, Position = 1)] | |
[int] | |
$Command = 0 | |
) | |
Switch-Prompt -Prompt Fast | |
$_starttime = [DateTime]::now | |
Write-Host -for Yellow "<Demo [$file] Started>" | |
try { | |
$_lines = Get-Content $file -ErrorAction Stop | |
} | |
catch { | |
Write-Warning "$file not found! Skipping demo" | |
} | |
# We use a FOR and an INDEX ($_i) instead of a FOREACH because | |
# it is possible to start at a different location and/or jump | |
# around in the order. | |
for ($_i = $Command; $_i -lt $_lines.count; $_i++) { | |
$_SimulatedLine = $("`n[$_i]PS> " + $($_Lines[$_i])) | |
Write-Host -NoNewLine $_SimulatedLine | |
# Put the current command in the Window Title along with the demo duration | |
$_Duration = [DateTime]::Now - $_StartTime | |
$Host.UI.RawUI.WindowTitle = "[{0}m, {1}s] {2}" -f [int]$_Duration.TotalMinutes, [int]$_Duration.Seconds, $($_Lines[$_i]) | |
if ($_lines[$_i].StartsWith("#")) { | |
continue | |
} | |
$_input = [System.Console]::ReadLine() | |
switch ($_input) { | |
"?" { | |
Write-Host -ForeGroundColor Yellow "Running demo: $file`n(q) Quit (!) Suspend (#x) Goto Command #x (fx) Find cmds using X`n(t) Timecheck (s) Skip (d) Dump demo" | |
$_i -= 1 | |
} | |
"q" { | |
Write-Host -ForeGroundColor Yellow "<Quit demo>" | |
return | |
} | |
"s" { | |
Write-Host -ForeGroundColor Yellow "<Skipping Cmd>" | |
} | |
"d" { | |
for ($_ni = 0; $_ni -lt $_lines.Count; $_ni++) { | |
if ($_i -eq $_ni) { | |
Write-Host -ForeGroundColor Red ("*" * 80) | |
} | |
Write-Host -ForeGroundColor Yellow ("[{0,2}] {1}" -f $_ni, $_lines[$_ni]) | |
} | |
$_i -= 1 | |
} | |
"t" { | |
$_Duration = [DateTime]::Now - $_StartTime | |
Write-Host -ForeGroundColor Yellow $("Demo has run {0} Minutes and {1} Seconds" -f [int]$_Duration.TotalMinutes, [int]$_Duration.Seconds) | |
$_i -= 1 | |
} | |
{$_.StartsWith("f")} { | |
for ($_ni = 0; $_ni -lt $_lines.Count; $_ni++) { | |
if ($_lines[$_ni] -match $_.SubString(1)) { | |
Write-Host -ForeGroundColor Yellow ("[{0,2}] {1}" -f $_ni, $_lines[$_ni]) | |
} | |
} | |
$_i -= 1 | |
} | |
{$_.StartsWith("!")} { | |
if ($_.Length -eq 1) { | |
Write-Host -ForeGroundColor Yellow "<Suspended demo - type ‘Exit’ to resume>" | |
$host.EnterNestedPrompt() | |
} | |
else { | |
trap [System.Exception] { | |
Write-Error $_;continue; | |
} | |
Invoke-Expression $($_.SubString(1) + "| out-host") | |
} | |
$_i -= 1 | |
} | |
{$_.StartsWith("#")} { | |
$_i = [int]($_.SubString(1)) - 1 | |
continue | |
} | |
default { | |
trap [System.Exception] { | |
Write-Error $_;continue; | |
} | |
Invoke-Expression $($_lines[$_i] + "| out-host") | |
$_Duration = [DateTime]::Now - $_StartTime | |
$Host.UI.RawUI.WindowTitle = "[{0}m, {1}s] {2}" -f [int]$_Duration.TotalMinutes, [int]$_Duration.Seconds, $($_Lines[$_i]) | |
[System.Console]::ReadLine() | |
} | |
} | |
} | |
$_Duration = [DateTime]::Now - $_StartTime | |
Write-Host -ForeGroundColor Yellow $("<Demo Complete {0} Minutes and {1} Seconds>" -f [int]$_Duration.TotalMinutes, [int]$_Duration.Seconds) | |
Write-Host -ForeGroundColor Yellow $([DateTime]::now) | |
} | |
function Stop-Demo { | |
demo -exit | |
} | |
function demo { | |
[CmdletBinding()] | |
Param ( | |
[parameter()] | |
[Alias('e')] | |
[switch] | |
$exit | |
) | |
Process { | |
if ($exit -and $null -ne $env:DemoInProgress) { | |
$env:DemoInProgress = $null | |
[System.Environment]::SetEnvironmentVariable('DemoInProgress',$null,[System.EnvironmentVariableTarget]::User) | |
. $profile.CurrentUserAllHosts | |
} | |
elseif (-not $exit -and $null -eq $env:DemoInProgress) { | |
[System.Environment]::SetEnvironmentVariable('DemoInProgress',(-not $exit),[System.EnvironmentVariableTarget]::User) | |
$env:DemoInProgress = -not $exit | |
Switch-Prompt Basic | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function USA { | |
Write-host "`n 'MURICA" | |
Write-host "------------------------" | |
Write-host "░░░░░░░░░░" -BackgroundColor Blue -NoNewline | |
Write-host " " -BackgroundColor red | |
Write-host "░░░░░░░░░░" -BackgroundColor Blue -NoNewline | |
Write-host " " -BackgroundColor White | |
Write-host "░░░░░░░░░░" -BackgroundColor Blue -NoNewline | |
Write-host " " -BackgroundColor red | |
Write-host " " -BackgroundColor White | |
Write-host " " -BackgroundColor red | |
Write-host " " -BackgroundColor White | |
Write-host " `n" -BackgroundColor red | |
} | |
function FRANCE { | |
Write-host "`n FRANCE" | |
Write-host "------------------------" | |
Write-host " " -BackgroundColor Blue -NoNewline | |
Write-host " " -BackgroundColor White -NoNewline | |
Write-host " " -BackgroundColor Red | |
Write-host " " -BackgroundColor Blue -NoNewline | |
Write-host " " -BackgroundColor White -NoNewline | |
Write-host " " -BackgroundColor Red | |
Write-host " " -BackgroundColor Blue -NoNewline | |
Write-host " " -BackgroundColor White -NoNewline | |
Write-host " " -BackgroundColor Red | |
Write-host " " -BackgroundColor Blue -NoNewline | |
Write-host " " -BackgroundColor White -NoNewline | |
Write-host " " -BackgroundColor Red | |
Write-host " " -BackgroundColor Blue -NoNewline | |
Write-host " " -BackgroundColor White -NoNewline | |
Write-host " " -BackgroundColor Red | |
} | |
function Fabulous { | |
Write-host "`n Extra Fabulous" | |
Write-host "------------------------" | |
Write-host " " -BackgroundColor Red | |
Write-host " " -BackgroundColor DarkRed | |
Write-host " " -BackgroundColor Yellow | |
Write-host " " -BackgroundColor Green | |
Write-host " " -BackgroundColor Blue | |
Write-host " `n" -BackgroundColor Magenta | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Disable-ProfileClear { | |
[System.Environment]::SetEnvironmentVariable("PSProfileClear", 0, [System.EnvironmentVariableTarget]::User) | |
$env:PSProfileClear = 0 | |
} | |
function Enable-ProfileClear { | |
[System.Environment]::SetEnvironmentVariable("PSProfileClear", 1, [System.EnvironmentVariableTarget]::User) | |
$env:PSProfileClear = 1 | |
} | |
if ($null -eq (Get-Command open -ErrorAction SilentlyContinue)) { | |
New-Alias -Name open -Value Invoke-Item -Scope Global -Force | |
} | |
function Invoke-Profile { | |
[CmdletBinding()] | |
Param ( | |
[parameter(Mandatory = $false,Position = 0)] | |
[ValidateSet("Fast","Slim","Full","Demo","macOS",$null)] | |
[String] | |
$Level = $null | |
) | |
. $profile.CurrentUserAllHosts $Level | |
} | |
function Disable-PoshGit { | |
$env:DisablePoshGit = $true | |
} | |
function Enable-PoshGit { | |
$env:DisablePoshGit = $false | |
} | |
function Syntax { | |
[CmdletBinding()] | |
param ( | |
$Command | |
) | |
$check = Get-Command -Name $Command | |
$params = @{ | |
Name = if ($check.CommandType -eq 'Alias') { | |
Get-Command -Name $check.Definition | |
} | |
else { | |
$Command | |
} | |
Syntax = $true | |
} | |
(Get-Command @params) -replace '(\s(?=\[)|\s(?=-))', "`r`n " | |
} | |
function Show-Colors ([Switch]$Grid) { | |
$colors = [enum]::GetValues([System.ConsoleColor]) | |
if ($Grid) { | |
Foreach ($bgcolor in $colors) { | |
Foreach ($fgcolor in $colors) { | |
Write-Host "$fgcolor|" -ForegroundColor $fgcolor -BackgroundColor $bgcolor -NoNewLine | |
} | |
Write-Host " on $bgcolor" | |
} | |
} | |
else { | |
$max = ($colors | ForEach-Object { "$_ ".Length } | Measure-Object -Maximum).Maximum | |
foreach ( $color in $colors ) { | |
Write-Host (" {0,2} {1,$max} " -f [int]$color,$color) -NoNewline | |
Write-Host "$color" -Foreground $color | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function global:Get-Prompt { | |
$i = 0 | |
$leadingWhiteSpace = $null | |
"function global:prompt {`n" + $((Get-Command prompt).Definition -split "`n" | ForEach-Object { | |
if (-not [String]::IsNullOrWhiteSpace($_)) { | |
if ($null -eq $leadingWhiteSpace) { | |
$leadingWhiteSpace = ($_ | Select-String -Pattern '^\s+').Matches[0].Value | |
} | |
$_ -replace "^$leadingWhiteSpace",' ' | |
"`n" | |
} | |
elseif ($i) { | |
$_ | |
"`n" | |
} | |
$i++ | |
}) + "}" | |
} | |
function global:Get-PSVersion { | |
[OutputType('System.String')] | |
[CmdletBinding()] | |
Param ( | |
[parameter(Position = 0)] | |
[AllowNull()] | |
[int] | |
$Places | |
) | |
Process { | |
$version = $PSVersionTable.PSVersion.ToString() | |
if ($PSBoundParameters.ContainsKey('Places') -and $null -ne $Places) { | |
$split = ($version -split '\.')[0..($Places - 1)] | |
if ("$($split[-1])".Length -gt 1) { | |
$split[-1] = "$($split[-1])".Substring(0,1) | |
} | |
$joined = $split -join '.' | |
if ($version -match '[a-zA-Z]+') { | |
$joined += "-$(($Matches[0]).Substring(0,1))" | |
if ($version -match '\d+$') { | |
$joined += $Matches[0] | |
} | |
} | |
$joined | |
} | |
else { | |
$version | |
} | |
} | |
} | |
function global:Test-IfGit { | |
[CmdletBinding()] | |
Param () | |
Process { | |
try { | |
$topLevel = git rev-parse --show-toplevel *>&1 | |
if ($topLevel -like 'fatal: *') { | |
$false | |
} | |
else { | |
$origin = git remote get-url origin | |
$repo = Split-Path -Leaf $origin | |
[PSCustomObject]@{ | |
TopLevel = (Resolve-Path $topLevel).Path | |
Origin = $origin | |
Repo = $(if ($repo -notmatch '(\.git|\.ssh|\.tfs)$') {$repo} else {$repo.Substring(0,($repo.LastIndexOf('.')))}) | |
} | |
} | |
} | |
catch { | |
$false | |
} | |
} | |
} | |
function global:Get-PathAlias { | |
[CmdletBinding()] | |
Param ( | |
[parameter(Position = 0)] | |
[string] | |
$Path = $PWD.Path, | |
[parameter(Position = 1)] | |
[string] | |
$DirectorySeparator = $global:PathAliasDirectorySeparator | |
) | |
Begin { | |
try { | |
$origPath = $Path | |
if ($null -eq $global:PSProfileConfig) { | |
$global:PSProfileConfig = @{ | |
_internal = @{ | |
PathAliasMap = @{ | |
'~' = $env:USERPROFILE | |
} | |
} | |
} | |
} | |
elseif ($null -eq $global:PSProfileConfig['_internal']) { | |
$global:PSProfileConfig['_internal'] = @{ | |
PathAliasMap = @{ | |
'~' = $env:USERPROFILE | |
} | |
} | |
} | |
elseif ($null -eq $global:PSProfileConfig['_internal']['PathAliasMap']) { | |
$global:PSProfileConfig['_internal']['PathAliasMap'] = @{ | |
'~' = $env:USERPROFILE | |
} | |
} | |
if ($gitRepo = Test-IfGit) { | |
$gitIcon = [char]0xe0a0 | |
$key = $gitIcon + $gitRepo.Repo | |
if (-not $global:PSProfileConfig['_internal']['PathAliasMap'].ContainsKey($key)) { | |
$global:PSProfileConfig['_internal']['PathAliasMap'][$key] = $gitRepo.TopLevel | |
} | |
} | |
$leaf = Split-Path $Path -Leaf | |
if (-not $global:PSProfileConfig['_internal']['PathAliasMap'].ContainsKey('~')) { | |
$global:PSProfileConfig['_internal']['PathAliasMap']['~'] = $env:USERPROFILE | |
} | |
Write-Verbose "Alias map => JSON: $($global:PSProfileConfig['_internal']['PathAliasMap'] | ConvertTo-Json -Depth 5)" | |
$aliasKey = $null | |
$aliasValue = $null | |
foreach ($hash in $global:PSProfileConfig['_internal']['PathAliasMap'].GetEnumerator() | Sort-Object {$_.Value.Length} -Descending) { | |
if ($Path -like "$($hash.Value)*") { | |
$Path = $Path.Replace($hash.Value,$hash.Key) | |
$aliasKey = $hash.Key | |
$aliasValue = $hash.Value | |
Write-Verbose "AliasKey [$aliasKey] || AliasValue [$aliasValue]" | |
break | |
} | |
} | |
} | |
catch { | |
Write-Error $_ | |
return $origPath | |
} | |
} | |
Process { | |
try { | |
if ($null -ne $aliasKey -and $origPath -eq $aliasValue) { | |
Write-Verbose "Matched original path! Returning alias base path" | |
$finalPath = $Path | |
} | |
elseif ($null -ne $aliasKey) { | |
Write-Verbose "Matched alias key [$aliasKey]! Returning path alias with leaf" | |
$drive = "$($aliasKey)\" | |
$finalPath = if ((Split-Path $origPath -Parent) -eq $aliasValue) { | |
"$($drive)$($leaf)" | |
} | |
else { | |
"$($drive)$([char]0x2026)\$($leaf)" | |
} | |
} | |
else { | |
$drive = (Get-Location).Drive.Name + ':\' | |
Write-Verbose "Matched base drive [$drive]! Returning base path" | |
$finalPath = if ($Path -eq $drive) { | |
$drive | |
} | |
elseif ((Split-Path $Path -Parent) -eq $drive) { | |
"$($drive)$($leaf)" | |
} | |
else { | |
"$($drive)..\$($leaf)" | |
} | |
} | |
if ($DirectorySeparator -notin @($null,([System.IO.Path]::DirectorySeparatorChar))) { | |
$finalPath.Replace(([System.IO.Path]::DirectorySeparatorChar),$DirectorySeparator) | |
} | |
else { | |
$finalPath | |
} | |
} | |
catch { | |
Write-Error $_ | |
return $origPath | |
} | |
} | |
} | |
function global:Get-Elapsed { | |
[CmdletBinding()] | |
param( | |
[Parameter()] | |
[int] | |
$Id, | |
[Parameter()] | |
[string] | |
$Format = "{0:h\:mm\:ss\.ffff}" | |
) | |
$null = $PSBoundParameters.Remove("Format") | |
$LastCommand = Get-History -Count 1 @PSBoundParameters | |
if (!$LastCommand) { | |
return "0:00:00.0000" | |
} | |
elseif ($null -ne $LastCommand.Duration) { | |
$Format -f $LastCommand.Duration | |
} | |
else { | |
$Duration = $LastCommand.EndExecutionTime - $LastCommand.StartExecutionTime | |
$Format -f $Duration | |
} | |
} | |
function global:Switch-Prompt { | |
[CmdletBinding()] | |
Param ( | |
[parameter(Position = 0,ValueFromPipeline)] | |
[ValidateSet('Basic','BasicPlus','Original','Clean','Fast','Demo','Slim','Rayner','Full','PowerLine')] | |
[String] | |
$Prompt = 'Basic', | |
[parameter()] | |
[Alias('ng')] | |
[switch] | |
$NoGit, | |
[parameter()] | |
[Alias('nc')] | |
[switch] | |
$NoClear | |
) | |
Begin { | |
if (-not $NoClear) { | |
if (-not (Test-Path Env:\PSProfileClear) -or (($env:PSProfileClear -as [int]) -as [bool])) { | |
Clear-Host | |
} | |
} | |
if (-not $PSBoundParameters.ContainsKey('Prompt') -and $MyInvocation.InvocationName -in @('Set-DemoPrompt','Start-Demo','demo')) { | |
$Prompt = 'Demo' | |
$NoGit = $true | |
} | |
if ($Prompt -eq 'Fast') { | |
$Prompt = 'Slim' | |
$NoGit = $true | |
} | |
elseif ($Prompt -in @('Clean','Basic')) { | |
$NoGit = $true | |
} | |
elseif ($Prompt -in @('Full','PowerLine')) { | |
Import-Module PowerLine | |
Set-PowerLinePrompt -PowerLineFont -Verbose:$false | |
} | |
if (-not $NoGit) { | |
Import-Module posh-git -Verbose:$false | |
$GitPromptSettings.EnableWindowTitle = "Repo Info: " | |
} | |
$global:PreviousPrompt = if ($global:CurrentPrompt) { | |
$global:CurrentPrompt | |
} | |
else { | |
$null | |
} | |
$global:CurrentPrompt = $Prompt | |
$global:_useGit = -not $NoGit | |
} | |
Process { | |
if ($Prompt) { | |
Write-Verbose "Setting prompt to [$Prompt]" | |
switch ($Prompt) { | |
Slim { | |
<# Appearance: | |
[#12] [0:00:00.0347] ~\Personal-Settings [master ≡ +3 ~3 -1 !] | |
[PS 6.2]> | |
#> | |
function global:prompt { | |
$lastStatus = $? | |
$lastColor = if ($lastStatus -eq $true) { | |
'Green' | |
} | |
else { | |
"Red" | |
} | |
Write-Host "[" -NoNewline | |
Write-Host -ForegroundColor Cyan "#$($MyInvocation.HistoryId)" -NoNewline | |
Write-Host "] " -NoNewline | |
Write-Host "[" -NoNewline | |
Write-Host -ForegroundColor $lastColor ("{0}" -f (Get-Elapsed)) -NoNewline | |
Write-Host "] [" -NoNewline | |
Write-Host ("{0}" -f $(Get-PathAlias)) -NoNewline -ForegroundColor DarkYellow | |
Write-Host "]" -NoNewline | |
if (Test-IfGit) { | |
Write-VcsStatus | |
} | |
Write-Host "`n[" -NoNewLine | |
$verColor = @{ | |
ForegroundColor = if ($PSVersionTable.PSVersion.Major -eq 7) { | |
'Yellow' | |
} | |
elseif ($PSVersionTable.PSVersion.Major -eq 6) { | |
'Magenta' | |
} | |
else { | |
'Cyan' | |
} | |
} | |
Write-Host @verColor ("PS {0}" -f (Get-PSVersion $global:PSProfileConfig.Settings.PSVersionStringLength)) -NoNewline | |
Write-Host "]" -NoNewLine | |
$('>' * ($nestedPromptLevel + 1) + ' ') | |
} | |
} | |
Clean { | |
$global:CleanNumber = 0 | |
function global:prompt { | |
$global:CleanNumber++ | |
-join @( | |
'[CLN#' | |
$global:CleanNumber | |
'] [' | |
[Math]::Round((Get-History -Count 1).Duration.TotalMilliseconds,0) | |
'ms] ' | |
$(Get-PathAlias) | |
("`n[PS {0}" -f (Get-PSVersion $global:PSProfileConfig.Settings.PSVersionStringLength)) | |
']>> ' | |
) | |
} | |
} | |
Basic { | |
function global:prompt { | |
"PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "; | |
# .Link | |
# https://go.microsoft.com/fwlink/?LinkID=225750 | |
# .ExternalHelp System.Management.Automation.dll-help.xml | |
} | |
} | |
BasicPlus { | |
function global:prompt { | |
-join @( | |
'<# PS {0} | ' -f (Get-PSVersion $global:PSProfileConfig.Settings.PSVersionStringLength) | |
Get-PathAlias | |
' #> ' | |
) | |
} | |
} | |
Original { | |
function global:prompt { | |
$ra = [char]0xe0b0 | |
$fg = @{ | |
ForegroundColor = $Host.UI.RawUI.BackgroundColor | |
} | |
$cons = if ($psEditor) { | |
'Code' | |
} | |
elseif ($env:ConEmuPID) { | |
'ConEmu' | |
} | |
else { | |
'PS' | |
} | |
switch ($PSVersionTable.PSVersion.Major) { | |
5 { | |
$idColor = 'Green' | |
$verColor = 'Cyan' | |
} | |
6 { | |
$idColor = 'Cyan' | |
$verColor = 'Green' | |
} | |
7 { | |
$idColor = 'Cyan' | |
$verColor = 'Yellow' | |
} | |
} | |
Write-Host @fg -BackgroundColor $idColor "$ra[$($MyInvocation.HistoryId)]" -NoNewline | |
Write-Host -ForegroundColor $idColor $ra -NoNewline | |
Write-Host @fg -BackgroundColor $verColor "$ra[$("PS {0}" -f (Get-PSVersion $global:PSProfileConfig.Settings.PSVersionStringLength))]" -NoNewline | |
Write-Host -ForegroundColor $verColor $ra -NoNewline | |
if ($global:_useGit -and $PWD.Path -notlike "G:\GDrive\GoogleApps*" -and (git config -l --local *>&1) -notmatch '^fatal') { | |
Write-Host @fg -BackgroundColor Yellow "$ra[$(Get-Elapsed) @ $(Get-Date -Format T)]" -NoNewline | |
Write-Host -ForegroundColor Yellow $ra -NoNewline | |
Write-VcsStatus | |
Write-Host "" | |
} | |
else { | |
Write-Host @fg -BackgroundColor Yellow "$ra[$(Get-Elapsed) @ $(Get-Date -Format T)]" -NoNewline | |
Write-Host -ForegroundColor Yellow $ra | |
} | |
Write-Host @fg -BackgroundColor Magenta "$ra[$(Get-PathAlias)]" -NoNewline | |
Write-Host -ForegroundColor Magenta $ra -NoNewline | |
Write-Host "`n[I " -NoNewline | |
Write-Host -ForegroundColor Red "$([char]9829)" -NoNewline | |
" $cons]$('>' * ($nestedPromptLevel + 1)) " | |
} | |
} | |
Rayner { | |
<# Adapted from @thomasrayner's dev-workstation prompt: | |
https://github.com/thomasrayner/dev-workstation/blob/master/prompt.ps1 | |
#> | |
<# Appearance (looks better in full color): | |
0004»1CPSGSuitemaster 0:00:00.018210:52:23 PM | |
PS 6.2> | |
#> | |
$forePromptColor = 0 | |
[System.Collections.Generic.List[ScriptBlock]]$global:PromptRight = @( | |
# right aligned | |
{ "$foreground;${errorStatus}m{0}" -f $lArrow } | |
{ "$foreground;${forePromptColor}m$background;${errorStatus}m{0}" -f $(Get-Elapsed) } | |
{ "$foreground;7m$background;${errorStatus}m{0}" -f $lArrow } | |
{ "$foreground;0m$background;7m{0}" -f $(get-date -format "hh:mm:ss tt") } | |
) | |
[System.Collections.Generic.List[ScriptBlock]]$global:PromptLeft = @( | |
# left aligned | |
{ "$foreground;${forePromptColor}m$background;${global:platform}m{0}" -f $('{0:d4}' -f $MyInvocation.HistoryId) } | |
{ "$background;22m$foreground;${global:platform}m{0}" -f $($rArrow) } | |
{ "$background;22m$foreground;${forePromptColor}m{0}" -f $(if ($pushd = (Get-Location -Stack).count) { | |
"$([char]187)" + $pushd | |
}) } | |
{ "$foreground;22m$background;5m{0}" -f $rArrow } | |
{ "$background;5m$foreground;${forePromptColor}m{0}" -f $($pwd.Drive.Name) } | |
{ "$background;14m$foreground;5m{0}" -f $rArrow } | |
{ "$background;14m$foreground;${forePromptColor}m{0}$escape[0m" -f $(Split-Path $pwd -leaf) } | |
) | |
function global:prompt { | |
$global:errorStatus = if ($?) { | |
22 | |
} | |
else { | |
1 | |
} | |
$global:platform = if ($isWindows) { | |
11 | |
} | |
else { | |
117 | |
} | |
$global:lArrow = [char]0xe0b2 | |
$global:rArrow = [char]0xe0b0 | |
$escape = "$([char]27)" | |
$foreground = "$escape[38;5" | |
$background = "$escape[48;5" | |
$prompt = '' | |
$gitTest = $global:_useGit -and $PWD.Path -notlike "G:\GDrive\GoogleApps*" -and (git config -l --local *>&1) -notmatch '^fatal' | |
if ($gitTest) { | |
$branch = git symbolic-ref --short -q HEAD | |
$aheadbehind = git status -sb | |
$distance = '' | |
if (-not [string]::IsNullOrEmpty($(git diff --staged))) { | |
$branchbg = 3 | |
} | |
else { | |
$branchbg = 5 | |
} | |
if (-not [string]::IsNullOrEmpty($(git status -s))) { | |
$arrowfg = 3 | |
} | |
else { | |
$arrowfg = 5 | |
} | |
if ($aheadbehind -match '\[\w+.*\w+\]$') { | |
$ahead = [regex]::matches($aheadbehind, '(?<=ahead\s)\d+').value | |
$behind = [regex]::matches($aheadbehind, '(?<=behind\s)\d+').value | |
$distance = "$background;15m$foreground;${arrowfg}m{0}$escape[0m" -f $rArrow | |
if ($ahead) { | |
$distance += "$background;15m$foreground;${forePromptColor}m{0}$escape[0m" -f "a$ahead" | |
} | |
if ($behind) { | |
$distance += "$background;15m$foreground;${forePromptColor}m{0}$escape[0m" -f "b$behind" | |
} | |
$distance += "$foreground;15m{0}$escape[0m" -f $rArrow | |
} | |
else { | |
$distance = "$foreground;${arrowfg}m{0}$escape[0m" -f $rArrow | |
} | |
[System.Collections.Generic.List[ScriptBlock]]$gitPrompt = @( | |
{ "$background;${branchbg}m$foreground;14m{0}$escape[0m" -f $rArrow } | |
{ "$background;${branchbg}m$foreground;${forePromptColor}m{0}$escape[0m" -f $branch } | |
{ "{0}$escape[0m" -f $distance } | |
) | |
$prompt = -join @($global:PromptLeft + $gitPrompt + { " " }).Invoke() | |
} | |
else { | |
$prompt = -join @($global:PromptLeft + { "$foreground;14m{0}$escape[0m" -f $rArrow } + { " " }).Invoke() | |
} | |
$rightPromptString = -join ($global:promptRight).Invoke() | |
$offset = $global:host.UI.RawUI.BufferSize.Width - 24 | |
$returnedPrompt = -join @($prompt, "$escape[${offset}G", $rightPromptString, "$escape[0m" + ("`n`r`PS {0}.{1}> " -f $PSVersionTable.PSVersion.Major,$PSVersionTable.PSVersion.Minor)) | |
$returnedPrompt | |
} | |
} | |
Demo { | |
<# Appearance: | |
CMD# [2] | Dir: [~\Personal-Settings] | Last: [0:00:00.0087] | Git: [master ≡ +3 ~3 -1 !] | |
PS [6.2]> | |
#> | |
function global:prompt { | |
$lastStatus = $? | |
Write-Host "CMD# " -NoNewline | |
Write-Host -ForegroundColor Green "[$($MyInvocation.HistoryId)] " -NoNewline | |
#Write-Host -ForegroundColor Cyan "[$((Get-Location).Path.Replace($env:HOME,'~'))] " -NoNewline | |
$lastColor = if ($lastStatus -eq $true) { | |
"Yellow" | |
} | |
else { | |
"Red" | |
} | |
Write-Host "| Dir: " -NoNewLine | |
Write-Host -ForegroundColor Cyan "[$(Get-PathAlias)] " -NoNewline | |
Write-Host "| Last: " -NoNewLine | |
Write-Host -ForegroundColor $lastColor "[$(Get-Elapsed)] " -NoNewline | |
if ($global:_useGit -and $PWD.Path -notlike "G:\GDrive\GoogleApps*" -and (git config -l --local *>&1) -notmatch '^fatal') { | |
Write-Host "| Git:" -NoNewLine | |
Write-VcsStatus | |
} | |
Write-Host "`nPS " -NoNewline | |
$verColor = if ($PSVersionTable.PSVersion.Major -lt 6) { | |
@{ | |
ForegroundColor = 'Cyan' | |
BackgroundColor = $host.UI.RawUI.BackgroundColor | |
} | |
} | |
elseif ($PSVersionTable.PSVersion.Major -eq 6) { | |
@{ | |
ForegroundColor = $host.UI.RawUI.BackgroundColor | |
BackgroundColor = 'Cyan' | |
} | |
} | |
elseif ($PSVersionTable.PSVersion.Major -eq 7) { | |
@{ | |
ForegroundColor = $host.UI.RawUI.BackgroundColor | |
BackgroundColor = 'Yellow' | |
} | |
} | |
Write-Host @verColor ("[{0}]" -f (Get-PSVersion $global:PSProfileConfig.Settings.PSVersionStringLength)) -NoNewline | |
('>' * ($nestedPromptLevel + 1)) + ' ' | |
} | |
} | |
PowerLine { | |
Set-PowerLinePrompt -PowerLineFont -SetCurrentDirectory -RestoreVirtualTerminal -Newline -Timestamp -Colors ([PoshCode.Pansies.RgbColor]::ConsolePalette) | |
Add-PowerLineBlock { if ($pushed = (Get-Location -Stack).count) { | |
"»$pushed" | |
} } -Index 1 | |
Add-PowerLineBlock { Write-VcsStatus } -Index 3 | |
} | |
Full { | |
if ( -not $env:ConEmuPID ) { | |
function global:prompt { | |
$E = "$([char]27)" | |
$F = "$E[38;5" | |
$B = "$E[48;5" | |
"$B;255m$F;0mI $F;1m$([char]9829) $F;0mPS $F;0m$B;255m$([char]8250)$E[0m " | |
} | |
} | |
else { | |
[ScriptBlock[]]$global:Prompt = @( | |
# right aligned | |
{ " " * ($Host.UI.RawUI.BufferSize.Width - 29) } | |
{ "$F;${er}m{0}" -f [char]0xe0b2 } | |
{ "$F;15m$B;${er}m{0}" -f $(if (@(get-history).Count -gt 0) { | |
(get-history)[-1] | ForEach-Object { "{0:c}" -f (new-timespan $_.StartExecutionTime $_.EndExecutionTime) } | |
} | |
else { | |
'00:00:00.0000000' | |
}) } | |
{ "$F;7m$B;${er}m{0}" -f [char]0xe0b2 } | |
{ "$F;0m$B;7m{0}" -f $(get-date -format "hh:mm:ss tt") } | |
# left aligned | |
{ "$F;15m$B;117m{0}" -f $('{0:d4}' -f $MyInvocation.HistoryId) } | |
{ "$B;22m$F;117m{0}" -f $([char]0xe0b0) } | |
{ "$B;22m$F;15m{0}" -f $(if ($pushd = (Get-Location -Stack).count) { | |
"$([char]187)" + $pushd | |
}) } | |
{ "$F;22m$B;5m{0}" -f $([char]0xe0b0) } | |
{ "$B;5m$F;15m{0}" -f $($pwd.Drive.Name) } | |
{ "$B;20m$F;5m{0}" -f $([char]0xe0b0) } | |
{ "$B;20m$F;15m{0}$E[0m" -f $(Split-Path $pwd -leaf) } | |
{ "$F;20m{0}$E[0m" -f $([char]0xe0b0) } | |
) | |
function global:prompt { | |
$global:er = if ($?) { | |
22 | |
} | |
else { | |
1 | |
} | |
$E = "$([char]27)" | |
$F = "$E[38;5" | |
$B = "$E[48;5" | |
-join $global:Prompt.Invoke() | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
Set-Alias -Name sprompt -Value Switch-Prompt -Option AllScope -Force | |
Set-Alias -Name pro -Value Switch-Prompt -Option AllScope -Force |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if ($null -ne (Get-Module PSReadline)) { | |
Set-PSReadLineKeyHandler -Chord Tab -Function MenuComplete | |
Set-PSReadLineOption -HistorySearchCursorMovesToEnd | |
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward | |
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward | |
Set-PSReadLineKeyHandler -Chord 'Ctrl+W' -Function BackwardKillWord | |
Set-PSReadLineKeyHandler -Chord 'Ctrl+z' -Function MenuComplete | |
Set-PSReadLineKeyHandler -Chord 'Ctrl+D' -Function KillWord | |
Set-PSReadLineKeyHandler -Chord 'Ctrl+D,Ctrl+C' -Function CaptureScreen | |
if ($PSVersionTable.PSVersion.Major -le 5 -or ($PSVersionTable.PSVersion.Major -ge 7 -and $IsWindows)) { | |
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")) | |
} | |
} | |
} | |
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 ($toMatch -ne $null -and $line[$cursor - 1] -eq $toMatch) { | |
[Microsoft.PowerShell.PSConsoleReadLine]::Delete($cursor - 1, 2) | |
} | |
else { | |
[Microsoft.PowerShell.PSConsoleReadLine]::BackwardDeleteChar($key, $arg) | |
} | |
} | |
} | |
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+(','Alt+{','Alt+[','Alt+"',"Alt+'" ` | |
-BriefDescription WrapSelection ` | |
-LongDescription "Put parenthesis/brackets/braces/quotes around the selection or entire line and move the cursor to after the closing parenthesis" ` | |
-ScriptBlock { | |
param($key, $arg) | |
switch -Regex ($key.KeyChar) { | |
'\(' { | |
$openChar = [char]'(' | |
$closeChar = [char]')' | |
break | |
} | |
'\{' { | |
$openChar = [char]'{' | |
$closeChar = [char]'}' | |
break | |
} | |
'\[' { | |
$openChar = [char]'[' | |
$closeChar = [char]']' | |
break | |
} | |
'\"' { | |
$openChar = $closeChar = [char]'"' | |
break | |
} | |
"\'" { | |
$openChar = $closeChar = [char]"'" | |
break | |
} | |
} | |
$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, $openChar + $line.SubString($selectionStart, $selectionLength) + $closeChar) | |
[Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($selectionStart + $selectionLength + 2) | |
} | |
else { | |
[Microsoft.PowerShell.PSConsoleReadLine]::Replace(0, $line.Length, $openChar + $line + $closeChar) | |
[Microsoft.PowerShell.PSConsoleReadLine]::EndOfLine() | |
} | |
} | |
# 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 ($alias -ne $null) { | |
$resolvedCommand = $alias.ResolvedCommandName | |
if ($resolvedCommand -ne $null) { | |
$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 ($commandAst -ne $null) { | |
$commandName = $commandAst.GetCommandName() | |
if ($commandName -ne $null) { | |
$command = $ExecutionContext.InvokeCommand.GetCommand($commandName, 'All') | |
if ($command -is [System.Management.Automation.AliasInfo]) { | |
$commandName = $command.ResolvedCommandName | |
} | |
if ($commandName -ne $null) { | |
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() | % { | |
[PSCustomObject]@{Key = $_.Key; Dir = $_.Value } } | | |
Format-Table -AutoSize | Out-Host | |
[Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt() | |
} | |
Set-PSReadLineOption -CommandValidationHandler { | |
param([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') | |
} | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
This is my ever growing collection of PowerShell / workstation configuration bits. | |
#> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment