Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save JudsonMurray/52fa576f44e1427601fdf604a83d7aa5 to your computer and use it in GitHub Desktop.
Save JudsonMurray/52fa576f44e1427601fdf604a83d7aa5 to your computer and use it in GitHub Desktop.

Revisions

  1. @shanselman shanselman revised this gist Oct 24, 2022. 1 changed file with 4 additions and 3 deletions.
    7 changes: 4 additions & 3 deletions Microsoft.PowerShell_profile.ps1
    Original file line number Diff line number Diff line change
    @@ -8,12 +8,13 @@ if ($host.Name -eq 'ConsoleHost')
    #Import-Module PSColors
    #Import-Module posh-git
    Import-Module -Name Terminal-Icons
    Import-Module oh-my-posh
    #Import-Module oh-my-posh
    Import-Module z
    set-alias desktop "Desktop.ps1"
    #Set-Theme ParadoxGlucose
    #Set-PoshPrompt -theme "D:\Dropbox\poshv3.json"

    oh-my-posh --init --shell pwsh --config "D:\Dropbox\poshv3.json" | Invoke-Expression
    oh-my-posh --init --shell pwsh --config "c:\Users\scottha\OneDrive\poshv4.json" | Invoke-Expression


    Register-ArgumentCompleter -Native -CommandName winget -ScriptBlock {
    @@ -693,4 +694,4 @@ Set-PSReadLineKeyHandler -Key Ctrl+Shift+t `
    [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert("dotnet test")
    [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
    }
    }
  2. @shanselman shanselman revised this gist Sep 1, 2021. 1 changed file with 27 additions and 72 deletions.
    99 changes: 27 additions & 72 deletions Microsoft.PowerShell_profile.ps1
    Original file line number Diff line number Diff line change
    @@ -5,59 +5,15 @@ if ($host.Name -eq 'ConsoleHost')
    {
    Import-Module PSReadLine
    }
    Import-Module PSColors
    #Import-Module PSColors
    #Import-Module posh-git
    Import-Module -Name Terminal-Icons
    Import-Module oh-my-posh
    set-alias desktop "Desktop.ps1"
    #Set-Theme ParadoxGlucose
    Set-PoshPrompt -theme "D:\Dropbox\poshv3.json"

    [ScriptBlock]$PromptHOLD = {
    $lastCommandSuccess = $?
    $realLASTEXITCODE = $global:LASTEXITCODE
    $errorCode = 0
    if ($lastCommandSuccess -eq $false) {
    #native app exit code
    if ($realLASTEXITCODE -is [int] -and $realLASTEXITCODE -gt 0) {
    $errorCode = $realLASTEXITCODE
    }
    else {
    $errorCode = 1
    }
    }

    $executionTime = -1
    $history = Get-History -ErrorAction Ignore -Count 1
    if ($null -ne $history -and $null -ne $history.EndExecutionTime -and $null -ne $history.StartExecutionTime) {
    $executionTime = ($history.EndExecutionTime - $history.StartExecutionTime).TotalMilliseconds
    }

    $startInfo = New-Object System.Diagnostics.ProcessStartInfo
    $startInfo.FileName = "D:\Dropbox\utils\posh-windows-amd64.exe"
    $cleanPWD = $PWD.ProviderPath.TrimEnd("\")
    $startInfo.Arguments = "-config=""D:\Dropbox\poshv3.json"" -error=$errorCode -pwd=""$cleanPWD"" -execution-time=$executionTime"
    $startInfo.Environment["TERM"] = "xterm-256color"
    $startInfo.CreateNoWindow = $true
    $startInfo.StandardOutputEncoding = [System.Text.Encoding]::UTF8
    $startInfo.RedirectStandardOutput = $true
    $startInfo.UseShellExecute = $false
    if ($PWD.Provider.Name -eq 'FileSystem') {
    $startInfo.WorkingDirectory = $PWD.ProviderPath
    }
    $process = New-Object System.Diagnostics.Process
    $process.StartInfo = $startInfo
    $process.Start() | Out-Null
    $standardOut = $process.StandardOutput.ReadToEnd()
    $process.WaitForExit()
    $standardOut
    $global:LASTEXITCODE = $realLASTEXITCODE
    #remove temp variables
    Remove-Variable realLASTEXITCODE -Confirm:$false
    Remove-Variable lastCommandSuccess -Confirm:$false
    }
    #Set-Item -Path Function:prompt -Value $Prompt -Force
    #Set-PoshPrompt -theme "D:\Dropbox\poshv3.json"

    oh-my-posh --init --shell pwsh --config "D:\Dropbox\poshv3.json" | Invoke-Expression


    Register-ArgumentCompleter -Native -CommandName winget -ScriptBlock {
    @@ -78,11 +34,6 @@ Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock {
    }
    }


    Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
    Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward


    # ---


    @@ -157,26 +108,6 @@ Set-PSReadLineKeyHandler -Key F7 `
    }
    }

    # 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+Shift+b `
    -BriefDescription BuildCurrentDirectory `
    -LongDescription "Build the current directory" `
    -ScriptBlock {
    [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert("dotnet build")
    [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
    }

    Set-PSReadLineKeyHandler -Key Ctrl+Shift+t `
    -BriefDescription BuildCurrentDirectory `
    -LongDescription "Build the current directory" `
    -ScriptBlock {
    [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert("dotnet test")
    [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
    }


    # CaptureScreen is good for blog posts or email showing a transaction
    # of what you did when asking for help or demonstrating a technique.
    @@ -739,3 +670,27 @@ Set-PSReadLineKeyHandler -Key Alt+a `
    }


    Set-PSReadLineOption -PredictionSource History
    Set-PSReadLineOption -PredictionViewStyle ListView
    Set-PSReadLineOption -EditMode Windows


    # 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+Shift+b `
    -BriefDescription BuildCurrentDirectory `
    -LongDescription "Build the current directory" `
    -ScriptBlock {
    [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert("dotnet build")
    [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
    }

    Set-PSReadLineKeyHandler -Key Ctrl+Shift+t `
    -BriefDescription BuildCurrentDirectory `
    -LongDescription "Build the current directory" `
    -ScriptBlock {
    [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert("dotnet test")
    [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
    }
  3. @shanselman shanselman revised this gist Apr 9, 2021. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions Microsoft.PowerShell_profile.ps1
    Original file line number Diff line number Diff line change
    @@ -7,6 +7,7 @@ if ($host.Name -eq 'ConsoleHost')
    }
    Import-Module PSColors
    #Import-Module posh-git
    Import-Module -Name Terminal-Icons
    Import-Module oh-my-posh
    set-alias desktop "Desktop.ps1"
    #Set-Theme ParadoxGlucose
  4. @shanselman shanselman created this gist Apr 9, 2021.
    740 changes: 740 additions & 0 deletions Microsoft.PowerShell_profile.ps1
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,740 @@
    using namespace System.Management.Automation
    using namespace System.Management.Automation.Language

    if ($host.Name -eq 'ConsoleHost')
    {
    Import-Module PSReadLine
    }
    Import-Module PSColors
    #Import-Module posh-git
    Import-Module oh-my-posh
    set-alias desktop "Desktop.ps1"
    #Set-Theme ParadoxGlucose
    Set-PoshPrompt -theme "D:\Dropbox\poshv3.json"

    [ScriptBlock]$PromptHOLD = {
    $lastCommandSuccess = $?
    $realLASTEXITCODE = $global:LASTEXITCODE
    $errorCode = 0
    if ($lastCommandSuccess -eq $false) {
    #native app exit code
    if ($realLASTEXITCODE -is [int] -and $realLASTEXITCODE -gt 0) {
    $errorCode = $realLASTEXITCODE
    }
    else {
    $errorCode = 1
    }
    }

    $executionTime = -1
    $history = Get-History -ErrorAction Ignore -Count 1
    if ($null -ne $history -and $null -ne $history.EndExecutionTime -and $null -ne $history.StartExecutionTime) {
    $executionTime = ($history.EndExecutionTime - $history.StartExecutionTime).TotalMilliseconds
    }

    $startInfo = New-Object System.Diagnostics.ProcessStartInfo
    $startInfo.FileName = "D:\Dropbox\utils\posh-windows-amd64.exe"
    $cleanPWD = $PWD.ProviderPath.TrimEnd("\")
    $startInfo.Arguments = "-config=""D:\Dropbox\poshv3.json"" -error=$errorCode -pwd=""$cleanPWD"" -execution-time=$executionTime"
    $startInfo.Environment["TERM"] = "xterm-256color"
    $startInfo.CreateNoWindow = $true
    $startInfo.StandardOutputEncoding = [System.Text.Encoding]::UTF8
    $startInfo.RedirectStandardOutput = $true
    $startInfo.UseShellExecute = $false
    if ($PWD.Provider.Name -eq 'FileSystem') {
    $startInfo.WorkingDirectory = $PWD.ProviderPath
    }
    $process = New-Object System.Diagnostics.Process
    $process.StartInfo = $startInfo
    $process.Start() | Out-Null
    $standardOut = $process.StandardOutput.ReadToEnd()
    $process.WaitForExit()
    $standardOut
    $global:LASTEXITCODE = $realLASTEXITCODE
    #remove temp variables
    Remove-Variable realLASTEXITCODE -Confirm:$false
    Remove-Variable lastCommandSuccess -Confirm:$false
    }
    #Set-Item -Path Function:prompt -Value $Prompt -Force



    Register-ArgumentCompleter -Native -CommandName winget -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)
    [Console]::InputEncoding = [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new()
    $Local:word = $wordToComplete.Replace('"', '""')
    $Local:ast = $commandAst.ToString().Replace('"', '""')
    winget complete --word="$Local:word" --commandline "$Local:ast" --position $cursorPosition | ForEach-Object {
    [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
    }
    }

    # PowerShell parameter completion shim for the dotnet CLI
    Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock {
    param($commandName, $wordToComplete, $cursorPosition)
    dotnet complete --position $cursorPosition "$wordToComplete" | ForEach-Object {
    [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
    }
    }


    Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
    Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward


    # ---


    # 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.

    # 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-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+Shift+b `
    -BriefDescription BuildCurrentDirectory `
    -LongDescription "Build the current directory" `
    -ScriptBlock {
    [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert("dotnet build")
    [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
    }

    Set-PSReadLineKeyHandler -Key Ctrl+Shift+t `
    -BriefDescription BuildCurrentDirectory `
    -LongDescription "Build the current directory" `
    -ScriptBlock {
    [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert("dotnet test")
    [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
    }


    # 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 Alt+B -Function SelectShellBackwardWord
    Set-PSReadLineKeyHandler -Key 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)

    $quote = $key.KeyChar

    $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 text is selected, just quote it without any smarts
    if ($selectionStart -ne -1)
    {
    [Microsoft.PowerShell.PSConsoleReadLine]::Replace($selectionStart, $selectionLength, $quote + $line.SubString($selectionStart, $selectionLength) + $quote)
    [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($selectionStart + $selectionLength + 2)
    return
    }

    $ast = $null
    $tokens = $null
    $parseErrors = $null
    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$tokens, [ref]$parseErrors, [ref]$null)

    function FindToken
    {
    param($tokens, $cursor)

    foreach ($token in $tokens)
    {
    if ($cursor -lt $token.Extent.StartOffset) { continue }
    if ($cursor -lt $token.Extent.EndOffset) {
    $result = $token
    $token = $token -as [StringExpandableToken]
    if ($token) {
    $nested = FindToken $token.NestedTokens $cursor
    if ($nested) { $result = $nested }
    }

    return $result
    }
    }
    return $null
    }

    $token = FindToken $tokens $cursor

    # If we're on or inside a **quoted** string token (so not generic), we need to be smarter
    if ($token -is [StringToken] -and $token.Kind -ne [TokenKind]::Generic) {
    # If we're at the start of the string, assume we're inserting a new string
    if ($token.Extent.StartOffset -eq $cursor) {
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$quote$quote ")
    [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1)
    return
    }

    # If we're at the end of the string, move over the closing quote if present.
    if ($token.Extent.EndOffset -eq ($cursor + 1) -and $line[$cursor] -eq $quote) {
    [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1)
    return
    }
    }

    if ($null -eq $token -or
    $token.Kind -eq [TokenKind]::RParen -or $token.Kind -eq [TokenKind]::RCurly -or $token.Kind -eq [TokenKind]::RBracket) {
    if ($line[0..$cursor].Where{$_ -eq $quote}.Count % 2 -eq 1) {
    # Odd number of quotes before the cursor, insert a single quote
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert($quote)
    }
    else {
    # Insert matching quotes, move cursor to be in between the quotes
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$quote$quote")
    [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor + 1)
    }
    return
    }

    # If cursor is at the start of a token, enclose it in quotes.
    if ($token.Extent.StartOffset -eq $cursor) {
    if ($token.Kind -eq [TokenKind]::Generic -or $token.Kind -eq [TokenKind]::Identifier -or
    $token.Kind -eq [TokenKind]::Variable -or $token.TokenFlags.hasFlag([TokenFlags]::Keyword)) {
    $end = $token.Extent.EndOffset
    $len = $end - $cursor
    [Microsoft.PowerShell.PSConsoleReadLine]::Replace($cursor, $len, $quote + $line.SubString($cursor, $len) + $quote)
    [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($end + 2)
    return
    }
    }

    # We failed to be smart, so just insert a single quote
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert($quote)
    }

    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 }
    }

    $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)
    {
    # Text is selected, wrap it in brackets
    [Microsoft.PowerShell.PSConsoleReadLine]::Replace($selectionStart, $selectionLength, $key.KeyChar + $line.SubString($selectionStart, $selectionLength) + $closeChar)
    [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($selectionStart + $selectionLength + 2)
    } else {
    # No text is selected, insert a pair
    [Microsoft.PowerShell.PSConsoleReadLine]::Insert("$($key.KeyChar)$closeChar")
    [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 ($toMatch -ne $null -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+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 ($tokenToChange -ne $null)
    {
    $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 [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 [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 [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+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()
    }

    # Auto correct 'git cmt' to 'git commit'
    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')
    }
    }
    }
    }
    }

    # `ForwardChar` accepts the entire suggestion text when the cursor is at the end of the line.
    # This custom binding makes `RightArrow` behave similarly - accepting the next word instead of the entire suggestion text.
    Set-PSReadLineKeyHandler -Key RightArrow `
    -BriefDescription ForwardCharAndAcceptNextSuggestionWord `
    -LongDescription "Move cursor one character to the right in the current editing line and accept the next word in suggestion when it's at the end of current editing line" `
    -ScriptBlock {
    param($key, $arg)

    $line = $null
    $cursor = $null
    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)

    if ($cursor -lt $line.Length) {
    [Microsoft.PowerShell.PSConsoleReadLine]::ForwardChar($key, $arg)
    } else {
    [Microsoft.PowerShell.PSConsoleReadLine]::AcceptNextSuggestionWord($key, $arg)
    }
    }

    # Cycle through arguments on current line and select the text. This makes it easier to quickly change the argument if re-running a previously run command from the history
    # or if using a psreadline predictor. You can also use a digit argument to specify which argument you want to select, i.e. Alt+1, Alt+a selects the first argument
    # on the command line.
    Set-PSReadLineKeyHandler -Key Alt+a `
    -BriefDescription SelectCommandArguments `
    -LongDescription "Set current selection to next command argument in the command line. Use of digit argument selects argument by position" `
    -ScriptBlock {
    param($key, $arg)

    $ast = $null
    $cursor = $null
    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$ast, [ref]$null, [ref]$null, [ref]$cursor)

    $asts = $ast.FindAll( {
    $args[0] -is [System.Management.Automation.Language.ExpressionAst] -and
    $args[0].Parent -is [System.Management.Automation.Language.CommandAst] -and
    $args[0].Extent.StartOffset -ne $args[0].Parent.Extent.StartOffset
    }, $true)

    if ($asts.Count -eq 0) {
    [Microsoft.PowerShell.PSConsoleReadLine]::Ding()
    return
    }

    $nextAst = $null

    if ($null -ne $arg) {
    $nextAst = $asts[$arg - 1]
    }
    else {
    foreach ($ast in $asts) {
    if ($ast.Extent.StartOffset -ge $cursor) {
    $nextAst = $ast
    break
    }
    }

    if ($null -eq $nextAst) {
    $nextAst = $asts[0]
    }
    }

    $startOffsetAdjustment = 0
    $endOffsetAdjustment = 0

    if ($nextAst -is [System.Management.Automation.Language.StringConstantExpressionAst] -and
    $nextAst.StringConstantType -ne [System.Management.Automation.Language.StringConstantType]::BareWord) {
    $startOffsetAdjustment = 1
    $endOffsetAdjustment = 2
    }

    [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($nextAst.Extent.StartOffset + $startOffsetAdjustment)
    [Microsoft.PowerShell.PSConsoleReadLine]::SetMark($null, $null)
    [Microsoft.PowerShell.PSConsoleReadLine]::SelectForwardChar($null, ($nextAst.Extent.EndOffset - $nextAst.Extent.StartOffset) - $endOffsetAdjustment)
    }